I have 2 boolean variables, for example:
boolean isWhite;
boolean isTall;
So I want to determine a different behavior for the 4 possible cases ({(isWhite, isTall), (!isWhite, isTall), (isWhite, !isTall), (!isWhite, !isTall)}).
1) Is there a more elegant and practical way to do it than with using if/else each time?
if(isWhite) {
if(isTall) {
// Case 1
}
else {
// Case 2
}
else {
if(isTall) {
// Case 3
}
else {
// Case 4
}
2) Would it be of any difference doing something like this instead?
if (isWhite && isTall)
// Case 1
if (isWhite && !isTall)
// Case 2
if (!isWhite && isTall)
// Case 3
if (!isWhite && !isTall)
// Case 4
Your second solution is more readable. But you should use if-else instead of just if-statements. Consider if the first case is already true. The other 3 if statements still will be computed. If you use if-else statements and the first case is true, the other 3 statements will be just skipped.
if (isWhite && isTall) {//case1}
else if (isWhite && !isTall) {//case2}
else if (!isWhite && isTall) {//case3}
else {//case4}
I would prefer the first if/else arrangement unless you can use an enum Say your booleans were a and b
enum Combination {
A_B, NA_B, A_NB, NA_NB;
}
where NA_NB is not A, not B.
switch(comb) {
case A_B:
//
break;
// more cases
case NA_NB:
//
break;
}
This scales a bit better when you have more boolean and it can also make combinations which are impossible clearer.
This lends itself to removing the if/else block entirely.
enum Combination implements Actionable {
A_B {
public void action(Arg arg) {
// something
}
},
NA_B {
public void action(Arg arg) {
// something
}
},
A_NB {
public void action(Arg arg) {
// something
}
},
NA_NB {
public void action(Arg arg) {
// something
}
};
}
Now instead of an if/else or switch you can just call
actionable.action(something);
You can also easily add combinations, possibly custom Actionable which were not part of the original library.
Another alternatve would be to convert them into ints (i.e. 0 and 1) and use switch statement to identify all the scenarios, e.g.:
public static void main(String[] args) throws Exception{
boolean white = true, tall = false;
StringBuilder result = new StringBuilder();
result.append(white ? 1 : 0);
result.append(tall ? 1 : 0);
switch(result.toString()){
case "00":
//do something
break;
case "01":
//do something
break;
case "10":
//do something
break;
case "11":
//do something
break;
}
}
This is an often seen pattern where properties define different cases, by some business logic (founded in the real world).
That kind of control flow is hard to test, to verify, to track bugs from.
The best way is to make it more or less a declarative list.
Maybe remotely something like:
{ false, false, (isWhite, isTall) -> { ... } },
{ false, true, (isWhite, isTall) -> { ... } },
{ true, false, (isWhite, isTall) -> { ... } },
{ true, true, (isWhite, isTall) -> { ... } },
(More readable to use enums.)
In this way you can create plugins (XML with cases), log better (handler class name). Especially this declarative list can serve as specification of business logic, readable by the customer. Therefore it would be fine if the picked handler is given a string ID+version that appears to the user in some form. For instance a form-version in a PDF.
It means change of code design. But helped me for instance in the case of many similar reports.
Yet another possibility is to calculate your caseNumber directly from the booleans :
int caseNumber = 1 + (isWhite ? 0 : 2) + (isTall ? 0 : 1);
Here's an example :
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
System.out.println(getCaseNumber(true,true));
System.out.println(getCaseNumber(true,false));
System.out.println(getCaseNumber(false,true));
System.out.println(getCaseNumber(false,false));
switch(getCaseNumber(true,false)){
case 1:
System.out.println("Case 1!");
break;
case 2:
System.out.println("Case 2!");
break;
case 3:
System.out.println("Case 3!");
break;
case 4:
System.out.println("Case 4!");
break;
}
}
private static int getCaseNumber(boolean bool1, boolean bool2)
{
return 1 + (bool1 ? 0 : 2) + (bool2 ? 0 : 1);
}
}
It outputs :
1
2
3
4
Case 2!
It's easier to iterate over all possibilities, it scales better with n booleans and it's easier to use with a switchstatement.
1 + is just here to match your case definition, in which (true,true) is Case 1.
You can remove it if you want caseNumber between 0 and 2**n-1.
How about this? Similar to the previous answers, but I use else if to shorten my code when handling the two instances in which the booleans don't have the same value.
if(isWhite && isTall){/**case 1*/}
else if(isWhite){/**case 2*/} // only need one boolean
else if(isTall){/**case 3*/} // on each of these lines
else{/**case 4*/}
Saves you a little typing :)
Related
I have 6 values in the enum and using 6 if-else is really a bad practice.
Can we implement this in any better way? Below is my scenario :
ExampleEnum value = getEnumValue();
if(ExampleEnum.A == value){
doA();
}else if(ExampleEnum.B == value){
doB();
}else if(ExampleEnum.C == value){
doC();
}else if(ExampleEnum.D == value){
doD();
}else if(ExampleEnum.E == value){
doE();
}else if(ExampleEnum.F == value){
doF();
}
I was thinking of switch, but is is not making much difference also i need to return a boolean value inside doA() depending on certain parameters.
Thanks in advance.
You have a few options:
A chain of else-ifs
Leave your code as-is. Hard to read and write.
Switch
switch (value) {
case A:
doA();
break;
case B:
doB();
break;
case C:
doC();
break;
case D:
doD();
break;
case E:
doE();
break;
case F:
doF();
break;
}
Note that this is the classic switch. If you have access to newer Java versions, it is probably possible to get rid of the breaks.
EnumMap
You can also create an EnumMap:
EnumMap<ExampleEnum, Runnable> enumMap = new EnumMap<>(Map.<ExampleEnum, Runnable>of(
ExampleEnum.A, Main::doA, // 'Main', or wherever your do* methods are.
ExampleEnum.B, Main::doB,
ExampleEnum.C, Main::doC, // I'm using method references. But you could
ExampleEnum.D, Main::doD, // also use lambda expressions: '() -> doD()'.
ExampleEnum.E, Main::doE,
ExampleEnum.F, Main::doF
));
ExampleEnum value = getEnumValue();
enumMap.get(value).run();
If you want to use a switch statement and you're on Java 12 or newer, consider using extended switch expressions that avoid the pitfalls of break statements:
switch (value) {
case A -> doA();
case B -> doB();
case C -> doC();
case D -> doD();
case E -> doE();
case F -> doF();
}
You can add the do method inside the enum.
public enum ExampleEnum {
A {
public void doIt() { ... }
},
B {
public void doIt() { ... }
},
...
abstract public void doIt();
}
ExampleEnum value = getEnumValue();
if (value != null) {
value.doIt();
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I've got a situation in which I need to check multiple conditions, where every combination has a different outcome. In my specific condition, I've got 2 variables, which are enum types, that can each be 2 different values.
enum Enum1
{
COND_1,
COND_2
}
enum EnumA
{
COND_A,
COND_B
}
Enum1 var1;
EnumA varA;
This gives me 4 possible conditions, which requires 4 different outcomes. I've come up with a few different ways of doing this, either using if statements or switch statements:
if(var1 == Enum1.COND_1 && varA == EnumA.COND_A)
{
// Code
}
else if(var1 == Enum1.COND_1 && varA == EnumA.COND_B)
{
// Code
}
else if(var1 == Enum1.COND_2 && varA == EnumA.COND_A)
{
// Code
}
else if(var1 == Enum1.COND_2 && varA == EnumA.COND_B)
{
// Code
}
Or:
switch(var1)
{
case COND_1:
switch(varA)
{
case COND_A:
// Code
break;
case COND_B:
// Code
break;
}
break;
case COND_2:
switch(varA)
{
case COND_A:
// Code
break;
case COND_B:
// Code
break;
}
break;
}
I've thought of others, but don't want to fill this up with code :P I'd like to know what the best way to do this is. I think the switch is a bit easier to read, but the ifs are shorter. I think it'd be really cool if switches could have multiple conditions, but I haven't heard of it. This also begs the question: what's the best way to do this with an arbitrary number of variables and possible values?
For your small use case I would probably go for nested if statements. But if you have plenty of enum constants, perhaps a pattern using streams could make your code easier to read and maintain (for a small performance penalty). You could solve it using a stream like this:
Stream.of(new Conditional(COND_1, COND_A, () -> {/* do something */}),
new Conditional(COND_1, COND_B, () -> {/* do something */}),
new Conditional(COND_2, COND_A, () -> {/* do something */}),
new Conditional(COND_2, COND_B, () -> {/* do something */}))
.filter(x -> x.test(var1, varA))
.findAny()
.ifPresent(Conditional::run);
That would require a supporting class:
class Conditional implements BiPredicate<Enum1, EnumA>, Runnable
{
private final Enum1 var1;
private final EnumA varA;
private final Runnable runnable;
public Conditional(Enum1 var1, EnumA varA, Runnable runnable) {
this.var1 = var1;
this.varA = varA;
this.runnable = runnable;
}
#Override
public boolean test(Enum1 enum1, EnumA enumA) {
return var1 == enum1 && varA == enumA;
}
#Override
public void run() {
runnable.run();
}
}
Performance differences are probably negligible here, so I would focus on shortness and readability. So I would just simplify the if's a bit by using temporary variables:
boolean is_1 = (var1 == Enum1.COND_1);
boolean is_A = (varA == EnumA.COND_A);
if(is_1 && is_A)
{
// Code
}
else if(is_1 && !is_A)
{
// Code
}
else if(!is_1 && is_A)
{
// Code
}
else if(!is_1 && !is_A)
{
// Code
}
I prefer the if variant without nesting, since it is short and you have all the conditions in one line.
When stopping through the code during debugging, it can get tedious though, since you have to step over all preceding conditions, which is O(n). When executing the code, this shouldn't matter since the compiler will probably optimize the code.
There is no obvious best way, so you will have to experiment a bit.
I definitely prefer the flat version, it could just use a little less duplication:
// If you can't make the variables final, make some final copies
final Enum1 var1 = Enum1.COND_2;
final EnumA varA = EnumA.COND_B;
class Tester { // You could also make an anonymous BiPredicate<Enum1, EnumA>
boolean t(Enum1 v1, EnumA vA) {
return var1 == v1 && varA == vA;
}
};
Tester tes = new Tester();
if (tes.t(Enum1.COND_1, EnumA.COND_A)) {
// code
} else if (tes.t(Enum1.COND_1, EnumA.COND_B)) {
// code
} else if (tes.t(Enum1.COND_2, EnumA.COND_A)) {
// code
} else if (tes.t(Enum1.COND_2, EnumA.COND_B)) {
// code
}
Run it here. You could maybe make it even shorter and less redundant by doing a static import of the enums to avoid mentioning the enum names, e.g. tes.t(COND_1, COND_B). Or if you're willing to give up some compile time safety you can pass a string which gets converted to the two enum values, e.g. tes.t("COND_1 COND_A") (the implementation is left to the reader).
Maybe crazy idea but you could construct an int or a byte using the flags and use it in a single switch.
private int getIntegerStateForConditions(boolean... conditions ){
int state = 0;
int position = 0;
for(boolean condition: conditions){
if(condition){
state = state || (1 << position++);
}
}
return state;
}
...
switch(getIntegerStateForCondition((var1 == Enum1.COND_1), (var2 == EnumA.COND_A)){
case 0: ... //both condition false
case 1: ... //first condition true second false
case 2: ... //first false, second true ...
}
...
I think this is very far from being clean code but it looks better.
If I were you I would rely on bit flags in order to have only one byte (as you have only 4 use cases) to deal with and use a switch statement on this byte to manage all your use cases.
Something like this:
private static final int COND_2 = 1;
private static final int COND_B = 2;
private byte value;
public void setValue(Enum1 enum1) {
if (enum1 == Enum1.COND_1) {
this.value &= ~COND_2;
} else {
this.value |= COND_2;
}
}
public void setValue(EnumA enumA) {
if (enumA == EnumA.COND_A) {
this.value &= ~COND_B;
} else {
this.value |= COND_B;
}
}
public Enum1 getEnum1() {
return (this.value & COND_2) == COND_2 ? Enum1.COND_2 : Enum1.COND_1;
}
public EnumA getEnumA() {
return (this.value & COND_B) == COND_B ? EnumA.COND_B : EnumA.COND_A;
}
Then your tests would be:
switch (value) {
case 0 :
// 1-A;
break;
case 1 :
// 2-A;
break;
case 2 :
// 1-B;
break;
case 3 :
// 2-B;
break;
}
I would personally prefer this:
if(understandableNameInContextName1(var1, varA))
{
// Code
}
else if(understandableNameInContextName2(var1, varA))
{
// Code
}
else if(understandableNameInContextName3(var1, varA))
{
// Code
}
else if(understandableNameInContextName4(var1, varA))
{
// Code
}
private boolean understandableNameInContextName1(Object var1, Object varA){
return (var1 == Enum1.COND_1 && varA == EnumA.COND_A);
}
private boolean understandableNameInContextName2(Object var1, Object varA){
return (var1 == Enum1.COND_1 && varA == EnumA.COND_B);
}
private boolean understandableNameInContextName3(Object var1, Object varA){
return (var1 == Enum1.COND_2 && varA == EnumA.COND_A);
}
private boolean understandableNameInContextName4(Object var1, Object varA){
return (var1 == Enum1.COND_2 && varA == EnumA.COND_B);
}
And the names of the methods could be like, isOrderShippedAndDelivered(), isRequestSendAndAckRecieved().
The reason is that this is going to make the code a lot more readable.
Unless you have data that leads you back to these if statement there is not going to be much gain optimizing these.
See:
https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil
Kind of depends on the complexity of the code and number of combinations but another option is a dictionary with the key comprising a Tuple of your enumerations and a value of a delegate to the code.
I am writing some java code to check multiple conditions by if-else. The code is working properly but it is hard to do unit test.
reads lines that contains keyword conditionOne, conditionTwo or other keywords. hasConditionOneEnabled and hasConditionTwoEnabled are boolean values.
My real code has more else if statements than the provide example.
Can anyone help? Or give me some hint how to make the code shorter then I can write unit test easier? Thanks
boolean a = false;
boolean b = false;
if(line.contains("conditionOne")){
if(hasConditionOneEnabled){
a = true;
}else{
b = true;
}
}else if (line.contains("conditionTwo")){
if(hasConditionTwoEnabled){
a = true;
}else{
b = true;
}
}else{
a = true;
b = true;
}
if(a && b){
// do something 1
}else if(!a && b){
// do something 2
}else if(a && !b){
// do something 3
}else{
//both false, do nothing
}
a and b cannot be both false after the set of if-else statements.
In the first two if's variable a will have the same value than the corresponding hasConditionXXEnabled and b will be set as the opposite. The default else will set both to true.
Consider the following code:
a = true;
b = true;
if(line.contains("conditionOne")){
a = hasConditionOneEnabled;
b = !a;
}
else if(line.contains("conditionTwo")){
a = hasConditionTwoEnabled;
b = !a;
}
if(a && b){
// do something 1
}
else if(b){
// do something 2
}
else{
// do something 3
}
// test it on different line String input and different int value returned...
int xxx(String line) {
if(line.contains("conditionOne")){
status = hasConditionOneEnabled?0:1;
} else if (line.contains("conditionTwo")){
status = hasConditionTwoEnabled?0:1;
} else{
status = -1;
}
return status;
}
// test it base on different status value..
switch (status) {
case 0: ...;
case 1: ...;
default: ...;
}
However, if your if-else pattern can be continuously repeat after some modification, you may just create different boolean funciton for it.
First of all both a and b can never be false, so your last else statement is redundant.
Your entire set of conditional statements can be reduced to an if - else if - else block. You don't need variables a and b since you are using them to do something else anyway. Besides vague variables names like a and b hinder readability.
Let me first show you the code and I'll walk you through it subsequently.
boolean lineContainsCond1 = line.contains("conditionOne");
boolean lineContainsCond2 = line.contains("conditionTwo");
boolean lineContainsNeitherCondition = !lineContainsCond1 && !lineContainsCond2;
boolean conditionsForSomething3 = (lineContainsCond1 && conditionOneEnabled) || (lineContainsCond2 && conditionTwoEnabled);
if(lineContainsNeitherCondition)
//do something 1 (Note: this is the same something 1 from your code)
else if(conditionsForSomething3)
//do something 3
else
//do something 2
lineContainsNeitherCondition is essentially both a and b being true in your code.
conditionsForSomething3 tantamounts to a!b.
If both lineContainsNeitherCondition and conditionsForSomething3 are false, we can derive the following conclusions:
Given lineContainsNeitherCondition is false, either lineContainsCond1 is true or lineContainsCond2 is true
Case 1 : lineContainsCond1 is true:
In this case, either conditionOneIsEnabled is true or conditionOneEnabled is false. If it were true, then conditionFOrSomething3 cannot be false, if it's false, then that leads to lineContainsCond && !conditionOneEnabled to be true which leads to b!a in the original code and thereby executes //something 2.
A similar argument can be made for Case 2 : lineContainsCond2 is true.
Why don't reduce the amount of if else statements in your code.
Try replacing the if else statements with private methods that return a boolean. Try to in cooperate the below methods or similar methods into your above code.
Having a look at mookito great for mocking and stubbing. If you have a big project with lots of Objects will save you hours maybe days.
private boolean doesLineContainCondition(String line, String searchPhrase) {
if(line.contains(searchPhrase) {
return true;
} else {
return false;
}
}
private boolean hasConditionBeenEnabled(boolean condition) {
if(condition) {
a = true;
}
else {
b= true;
}
}
In my Java app, I have a switch method, the app needs to loop through all the cases in the switch, but the switch method keeps changing as my app develops, so I wonder if there is a way to auto detect how many cases there are in the switch and loop through all of them.
void RunAllCases(){
for (int i=0;i< ?? ;i++) SwitchMethod(i);
}
...
int SwitchMethod(int I)
{
switch (I) {
case 0 : return x;
case 1 : return y;
...
case 200 : return xx;
...
case 360 : return yy;
...
case 778899 : return nnnnn;
...
default : return z;
}
}
x, y, xx, yy, etc. are some calculated int values.
The short answer - no.
The slightly longer answer - not with an int. What you could do, though, is define an enum and pass that to the switchMethod. Then it can easily be iterated over by calling values():
public enum SwitchCases {
Case1, Case2, etc;
}
void runAllCases() {
for (SwitchCases sc : SwitchCases.values()) {
switchMethod(sc);
}
}
int switchMethod(SwitchCases sc) {
switch (sc) {
case Case1: return x;
case Case2: return y;
// etc...
}
}
If your app has all these switch statements, and you want to 'hit' all of them, then why not just define a method that calls each of them directly, in turn?
First of all, your requirement in this question is the switch case itself so we can't write anything inside the switch case. And you can't detect the number of checks inside the switch from outside.
Otherwise, if you yourself is writing the switch case then u can write all the cases without break and while calling call the first case and it will execute all the cases.
I learned about terminary expression, but what I want is a little different.
I have the following:
int MODE = getMyIntValue();
I do comparison as the following:
if(MODE == 1 || MODE == 2 || MODE == 3) //do something
I would like to know if there is a short way of doing this, I tried something like this but it didn't work:
if(MODE == 1 || 2 || 3) //do something
There is a short|quick way of doing it? I like quick "ifs" because it makes the code more clear, for example, it is more clear this:
System.out.println(MODE == 1 ? text1 : text2):
Than this:
if(MODE == 1) System.out.println(text1):
else System.out.println(text1):
Thanks in advance!
May be you can do something like this
System.out.println(Mode == 1 ? "1" : Mode == 2 ? "2" : "3");
switch-case also makes code more readable than multiple if-else
Well, if you don't mind the boxing hit, you could use a set which you prepared earlier:
// Use a more appropriate name if necessary
private static final Set<Integer> VALID_MODES
= new HashSet<>(Arrays.asList(1, 2, 3));
...
if (VALID_MODES.contains(mode)) {
}
You could use an int[] and a custom "does this array contain this value" method if you wanted... it would be O(N) or O(log N) for a binary search, but I suspect we're talking about small sets anyway.
I strongly recommend to use a more typed approach:
public class QuickIntSample {
enum Modes {
ONE(1),TWO(2),THREE(3); // you may choose more useful and readable names
int code;
private Modes(int code) {
this.code = code;
}
public static Modes fromCode(final int intCode) {
for (final Modes mode : values()) {
if (mode.code == intCode) {
return mode;
}
}
return null;
}
} // -- END of enum
public static void main(String[] args) {
int mode = 2;
if( Modes.fromCode(mode) == Modes.TWO ) {
System.out.println("got code 2");
}
}
}