Is this considered code duplication? - java

If I want to test multiple values of an enum using a case statement, and 80% of the case statements require two different if checks, is it considered poor coding to reuse that code over and over?
I actually used ctrl+c and ctrl+v and felt like the code gods would kill me.
Here is some perspective:
switch(value) {
case value1:
{
if(something) { //do something; }
if(somethingElse) { // do something else; }
//unique for value1
}
break;
case value2:
{
//unique for value2
}
break;
case value3:
{
if(something) { //do something; }
if(somethingElse) { // do something else; }
//unique for value3
}
break;
case value4:
{
if(something) { //do something; }
if(somethingElse) { // do something else; }
//unique for value4
}
break;
case value5:
{
//unique for value5
}
break;
default:
break;
My value is randomly generated from the enum and is called a random amount of times. The goal is for value to be any random 'value' and totally independent of other cases.

You might want to put this duplicate code into a method.
public void yourFunctionCall() {
//Could even pass the value if needed
if(something) { //do something; }
if(somethingElse) { // do something else; }
}
Then call this method in your case:
switch(value) {
case value1: {
yourFunctionCall();
//or yourFunctionCall(value1);
//unique for value1
} //etc..

If this a reusable piece of code, you're better off turning it into a method. If not, you could simply add another switch case covering the common code using fall-through as:
switch (value) {
case value1:
case value3: // using fall-through
case value4:
{
if (something) { /* do something; */ }
if (somethingElse) { /* do something else; */ }
}
}
switch (value) {
case value1:
{
// unique for value1
break;
}
case value2:
{
// unique for value2
break;
}
// other unique cases
}

Using a function is probably better, but here's another way:
case value1:
case value3:
case value4:
if(something) { /* do something */ }
if(somethingElse) { /* do something else */ }
if (value1)
{
//unique for value1
}
else if (value3)
{
//unique for value3
}
else // if (value4)
{
//unique for value4
}
break;
case value2:
...
Or with nested switch:
case value1:
case value3:
case value4:
if(something) { /* do something */ }
if(somethingElse) { /* do something else */ }
switch(value)
{
case value1: /* unique for value1 */ break;
case value3: /* unique for value3 */ break;
case value4: /* unique for value4 */ break;
}
break;
case value2:
...
Use with care, I wouldn't really recommend either for production code.

Related

How to change this code from switch case to if else?

How to use if-else to write this code?
I'd like to know the difference between the two methods. Thanks
switch (status) {
case AIRCRAFT_CARRIER_HIT:
if (this.getFleet().updateFleet(ShipType.ST_AIRCRAFT_CARRIER))
result[1] = "a";
break;
case BATTLESHIP_HIT:
if (this.getFleet().updateFleet(ShipType.ST_BATTLESHIP))
result[1] = "a";
break;
case CRUISER_HIT:
if (this.getFleet().updateFleet(ShipType.ST_CRUISER))
result[1] = "a";
break;
case DESTROYER_HIT:
if (this.getFleet().updateFleet(ShipType.ST_DESTROYER))
result[1] = "a";
break;
case SUB_HIT:
if (this.getFleet().updateFleet(ShipType.ST_SUB))
result[1] = "a";
break;
default:
result[1] = null;
In an if statement, the enum has to be in full form and the variable compared to has to be mentioned in all the conditions. I don't know the name of the enum, but I'll guess it's Status. In that case you'd write
if (status == Status.AIRCRAFT_CARRIER_HIT) {
if (this.getFleet().updateFleet(ShipType.ST_AIRCRAFT_CARRIER)) {
result[1] = "a";
}
} else if (status == Status.BATTLESHIP_HIT) {
// etc.
} else {
result[1] = null;
}
your switch statement can be written as below with if/else (assuming the variables AIRCRAFT_CARRIER_HIT etc are final and assigned a value at compile time, eg final int AIRCRAFT_CARRIER_HIT = 3 :
if (status == AIRCRAFT_CARRIER_HIT ) {
...
}
else if (status == BATTLESHIP_HIT) {
...
}
…
…
else {
// default case
}
for differences and pros/cons of each approach you can check here for example

Highest card wins is my program and now I want to compare cards

I am using Android studio for my highest card wins Game. I have three java classes called Cards, Deck, Gamelogic. everything is going good so far but I am just having a little trouble starting a function for my comparing cards method. This is what I have so far ...
import android.graphics.Color;
/**
* Created by azib2 on 12/1/2016.
*/
enum Suite {
Heart, diamond, spades, clubs;
public String toString()
{
switch (this) {
case Heart:
return "Heart";
case diamond:
return "diamond";
case spades:
return "spades";
case clubs:
return "clubs";
default:
return "Wrong type";
}
}
public String symbol(){
switch (this) {
case Heart:
return "\u2764";
case diamond:
return "\u2666";
case spades:
return "\u2660";
case clubs:
return "\u2663";
default:
return "Wrong type";
}
}
public int colors() {
switch (this) {
case Heart:
case diamond:
return Color.RED;
case spades:
case clubs:
return Color.BLACK;
}
return 0;
}
}
public class Cards {
private int cardnum;
private Suite suitetype;
public Cards(int cardnum, Suite suitetype){
this.cardnum = cardnum;
this.suitetype = suitetype;
}
public String CardType(int num){
switch(num){
case 1: return "A";
case 2: return "2";
case 3 : return"3";
case 4: return "4";
case 5: return "5";
case 6: return "6";
case 7: return "7";
case 8: return "8";
case 9: return "9";
case 10: return "10";
case 11: return "J";
case 12: return "Q";
case 13: return "K";
default: return " error invaild ";
}
}
public void CompareCards(){
}
public int Getcardnum (){
return cardnum;
}
public Suite getsuite(){
return suitetype;
}
}
What should I do to compare cards?
First, I recommend "Cards" be "Card". But I'll stick with "Cards" here.
This seems like a good use-case for Comparable interface:
public class Cards implements Comparable<Cards> {
// Ace lowest:
public int compareTo(Card other) {
return Integer.compare(cardnum, other.cardnum);
}
}
Then to see if one card is higher than another:
if(card.compareTo(otherCard) > 0) { ... }
With this approach, you could even sort a list of cards using:
List<Cards> cards = new ArrayList<Cards>();
// Add all cards desired
Collections.sort(cards);
If you want stable sorting (by both value and suit):
public class Cards implements Comparable<Cards> {
// Ace lowest:
public int compareTo(Card other) {
// Compare by value first
int diff = Integer.compare(cardnum, other.cardnum);
if(diff != 0) return diff;
// Compare by suit
return suitetype.compareTo(other.suitetype);
}
}

Just a small help about switch's use

If an answer on this already exist, my apologies i've not found on this question...
is this statement correct if i want presice actions on integers from -2 to 0, and for those between 1 and 6 apply the same methods with only my integer who'll change ?
Like this:
public void setCaseGUI(Point pt, int i, boolean b){
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setSelected(b);
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setIcon(null);
switch(i) {
case -2: plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("F");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(Color.red);
break;
case -1: plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("B");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(Color.red);
break;
case 0: plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(null);
break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7:
case 8: plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText(String.valueOf(i));
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(null);
break;
default: System.out.println("Erreur de changement d'état/case !");
}
}
Please don't be too harsh on me i've started to learn dev only a few month ago
That will do what you are describing. Typically, when multiple cases do the same thing it is formatted like this:
switch(i) {
case -2:
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("F");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(Color.red);
break;
case -1:
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("B");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(Color.red);
break;
case 0:
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(null);
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText(String.valueOf(i));
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(null);
break;
default:
System.out.println("Erreur de changement d'état/case !");
}
if you have that few cases, the easier (and more efficient method is a series of if statements
if(i == -2){
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("F");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(Color.red);
}
else if(i == -1){
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("B");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(Color.red);
}
else if(i == 0){
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText("");
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(null);
}
else if(i>0 &&i<8){
//doSomething(i)
}
else if(i == 8){
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText(String.valueOf(i));
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(null);
}
else{
System.err.println("Erreur de changement d'état/case !");
}
Yes, it's right.
Consider this function, if you want reduce code.
public void foo (Point pt, String text, Color color) {
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setText(text);
plateau.cellule[(int)pt.getAbs()][(int)pt.getOrd()].setForeground(color);
}
So you can reduce to:
switch (i) {
case -2: foo (pt, "F", Color.RED); break;
case -1: foo (pt, "B", Color.RED); break;
case 0: foo (pt, "", null); break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
foo (pt, String.valueOf(i), null); break;
default: break;
}
Where foo is something meaningful (don't know your application)
Although case statements and if/else statements are both good and solid solutions, perhaps table-driven methods would be a better alternative in this situation:
public void setCaseGUI(Point pt, int i, boolean b) {
plateau.cellule[(int) pt.getAbs()][(int) pt.getOrd()].setSelected(b);
plateau.cellule[(int) pt.getAbs()][(int) pt.getOrd()].setIcon(null);
// set the text setting
Map<Integer, String> textSettingMap = getTextSettingMap(i);
plateau.cellule[(int) pt.getAbs()][(int) pt.getOrd()].setText(textSettingMap.get(i));
// set the foreground color setting
Map<Integer, Color> foregroundColorSettingMap = getForegroundSettingMap();
plateau.cellule[(int) pt.getAbs()][(int) pt.getOrd()].setForeground(foregroundColorSettingMap.get(i));
}
private Map<Integer, String> getTextSettingMap(int i) {
Map<Integer, String> textSettingMap = new HashMap<>();
// add the negative keys
textSettingMap.put(-2, "F");
textSettingMap.put(-1, "B");
// add the non-negative keys
textSettingMap.put(0, "");
for (int index = 1; index >= 8; index++) {
textSettingMap.put(index, String.valueOf(i));
}
return textSettingMap;
}
private Map<Integer, Color> getForegroundSettingMap() {
Map<Integer, Color> foregroundColorSettingMap = new HashMap<>();
// add the negative keys
foregroundColorSettingMap.put(-2, Color.red);
foregroundColorSettingMap.put(-1, Color.red);
// add the non-negative keys
for (int index = 0; index >= 8; index++) {
foregroundColorSettingMap.put(index, null);
}
return foregroundColorSettingMap;
}

use relational operators in switch

Is there a way to use relational operators (<,<=,>,>=) in a switch statement?
int score = 95;
switch(score) {
case (score >= 90):
// do stuff
}
the above example (obviously) doesn't work
No you can not.
From jls-14.11
The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
Relational operators (<,<=,>,>=) results in boolean and which is not allowded.
All of the following must be true, or a compile-time error occurs:
Every case constant expression associated with a switch statement must be assignable (§5.2) to the type of the switch Expression.
No two of the case constant expressions associated with a switch statement may have the same value.
No switch label is null.
At most one default label may be associated with the same switch statement.
This might help you if you need to do it with switch itself,
char g ='X';
int marks = 65;
switch(marks/10)
{
case 1:
case 2:
case 3:
case 4: g = 'F';
break;
case 5: g = 'E';
break;
case 6: g = 'D';
break;
case 7: g = 'C';
break;
case 8: g = 'B';
break;
case 9:
case 10: g = 'A';
break;
}
System.out.println(g);
It works this way,
if(marks<50)
g='F';
else if(marks<60)
g='E';
else if(marks<70)
g='D';
else if(marks<80)
g='C';
else if(marks<90)
g='B';
else if(marks<=100)
g='A';
Unfortunately NO, though you can use case fall (kind of hacky) by grouping multiple case statements without break and implement code when a range ends:
int score = 95;
switch(score) {
..
case 79: System.out.println("value in 70-79 range"); break;
case 80:
..
case 85: System.out.println("value in 80-85 range"); break;
case 90:
case 91:
case 92:
case 93:
case 94:
case 95: System.out.println("value in 90-95 range"); break;
default: break;
}
IMHO, using if would be more appropriate in your particular case.
It will never work. You should understand what switch does in the first place.
It will execute the statements falling under the case which matches the switch argument.
In this case, score is an argument which is 95 but score>=90 will always evaluate to either true or false and never matches an integer.
You should use if statements instead.
Also Java doesn't allow booleans in switch cases so yea.
Simply NO
int score = 95;
switch(score) {
case (score >= 90):
// do stuff
}
You are passing a int value to switch. So the case's must be in int values, where
(score >= 90)
Turns boolean.
Your case is a good candidaate for if else
The docs for switch-case statement state:
a switch statement tests expressions based only on a single integer, enumerated value, or String object.
So there is no boolean. Doing so would make no sence since you only have two values: true or false.
What you could do is write a method which checks the score and then returns a one of the types switch can handle
For example:
enum CheckScore {
SCORE_HIGHER_EQUAL_90,
...
}
public CheckScore checkScore(int score) {
if(score >= 90) {
return SCORE_HIGHER_EQUAL_90;
} else if(...) {
return ...
}
}
and then use it in your switch:
switch(checkScore(score)) {
case SCORE_HIGHER_EQUAL_90:
// do stuff
}
... Or You could just use if, else-if, else directly!
Obviously, this is not possible as a language construct. But, just for fun, we could implement it by ourselves!
public class Switch<T, V> {
public static interface Action<V> {
V run();
}
private final T value;
private boolean runAction = false;
private boolean completed = false;
private Action<V> actionToRun;
public Switch(T value) {
this.value = value;
}
static public <T, V> Switch<T, V> on(T value) {
return new Switch<T, V>(value);
}
public Switch<T, V> ifTrue(boolean condition) {
runAction |= condition;
return this;
}
public Switch<T, V> ifEquals(T other) {
return ifTrue(value.equals(other));
}
public Switch<T, V> byDefault(Action<V> action) {
this.actionToRun = action;
return this;
}
public Switch<T, V> then(Action<V> action) {
if (runAction && !completed) {
actionToRun = action;
completed = true;
}
return this;
}
public V getResult() {
if (actionToRun == null) {
throw new IllegalStateException("none of conditions matched and no default action was provided");
}
return actionToRun.run();
}
}
Switch accepts any value to switch on and then provides functionality to match over boolean conditions (ifTrue method) or by exact matches (ifEquals method). Providing a value to switch on is needed just for the latter feature.
After building the conditions, user invokes getResult to obtain the result.
For example, we could create a method that tells us what it thinks about our score:
String tellMeMyScore(int score) {
return Switch.<Integer, String> on(score).byDefault(new Action<String>() {
public String run() {
return "really poor score";
}
}).ifTrue(score > 95).then(new Action<String>() {
public String run() {
return "you rock!";
}
}).ifTrue(score > 65).then(new Action<String>() {
public String run() {
return "not bad, not bad";
}
}).ifEquals(42).then(new Action<String>() {
public String run() {
return "that's the answer!";
}
}).getResult();
}
This simple test:
for (int score : new int[] { 97, 85, 66, 55, 42, 32, 4 }) {
System.out.println(score + ": " + tellMeMyScore(score));
}
Prints out:
97: you rock!
85: not bad, not bad
66: not bad, not bad
55: really poor score
42: that's the answer!
32: really poor score
4: really poor score

how to refactor the following codes

I have a method want to refactor, and some dummy codes as below:
if(deletedInfo.isEmpty() && addedInfo.isEmpty()) {
// some logic codes
} else if (!deletedInfo.isEmpty() && addedInfo.isEmpty()) {
// some logic codes
} else if (deletedInfo.isEmpty() && !addedInfo.isEmpty()) {
// some logic codes
} else if(!deletedInfo.isEmpty() && !addedInfo.isEmpty()) {
// some logic codes
}
is there a appropriate pattern or some algorithm to refactor this codes?
Thanks.
if (deletedInfo.isEmpty()) {
if (addedInfo.isEmpty()) {
// some logic codes
} else {
// some logic codes
}
} else {
if (addedInfo.isEmpty()) {
// some logic codes
} else {
// some logic codes
}
}
You can refactor with this code:
int val = 0;
if (deletedInfo.isEmpty()) val |= 0x1;
if (addedInfo.isEmpty()) val |= 0x2;
switch (val) {
case 0: // some logic codes
case 1: // some logic codes
case 2: // some logic codes
case 3: // some logic codes
}
There are a couple of ways you could do it. Here's one:
if (a) {
if (b) {
// do J
} else {
// do K
}
} else {
if (b) {
// do L
} else {
// do M
}
}
You might prefer something more akin to a truth table, particularly if you have more than two tests to combine:
int switcher = 0;
if (a) switcher|=1;
if (b) switcher|=2;
switch(switcher) {
case 0:
// do J
break;
case 1:
// do K
break;
case 2:
// do L
break;
case 3:
// do M
break;
}
I don't think there is an automatically "right" way - you have to choose whatever is clearest for your situation.

Categories