This question already has answers here:
What is the benefit of terminating if … else if constructs with an else clause?
(13 answers)
Closed 6 years ago.
I was thinking the other day about the creation of "else-if" statements and why the way of its execution causes each event to be guaranteed mutually exclusive.
For example:
if(condition A)
//condition
else if(condition B)
//will run if condition A is false and condition B is true
else if(condition C)
//will run if condition A is false and condition B is false and condition C is true
else if(condition D)
//will run if all the above conditions are false and condition D is true.
I would think it would make more sense for all the "else" statements to be checked if condition A is not true, and not just stop if either B or C are true. My intuition thinks it would be more natural to have the above code be equivalent to this:
if(condition A)
//condition
else {
if(condition B)
//...
if(condition C)
//...
if(condition D)
//...
}
So therefore, why do we define else-if the way we do? Is it to circumvent unnecessary nesting of if-else statements? I just think it is ambiguous and would make sense to have it be equivalent to my second code snippet.
Edit: to clear up confusion, I completely understand that these two statements are not always equivalent. My question is primarily asking why else-if is defined such that the first statement is not always equivalent to the second statement? I'm trying to understand why else-if runs the way it does.
Edit 2: I think I finally understand the underlying essence of my question. Generally, "else" checks if the above statement is false, and if it is, it runs the statement. However, in the case of elif, it checks to see if all the above statements are false before running. This is different from the duplicate question as it asks about the nature of if-else itself, rather than its exhaustiveness.
EDIT 3: I have opened a new question which is hopefully clearer, found here.
The reason one would prefer one style over the other is to ensure either the presence or lack of mutual exclusion when testing the conditions.
If it is the case that Condition B, C, or D are not mutually exclusive with one another, then...
...in the first scenario, only Condition B would fire, due to the mutual exclusivity of the else if statement.
...in the second scenario, Conditions B, C, and D would fire, due to the fact that they are not mutually exclusive due to the if statement.
Ultimately it depends on what you want to do. You may want to run multiple statements in this fashion. However, you probably don't. Fashioning your statements in a mutually exclusive way ensures that you don't run into strange logical bugs when you get a result or state that you didn't expect.
If you take your nesting approach, and apply it consistently, you would actually come up with this:
if (condition A) {
// A
} else {
if (condition B) {
// B
} else {
if (condition C) {
// C
} else {
if (condition D) {
// D
}
}
}
}
Each if gets treated the same way. The first if statement doesn't have any special ability to remove the else block from all the other if statements. The grammar you suggest gives else an inconsistent meaning.
Let's take a basic example.
Assume, You want to award a grade according to the score of the student and score is 60.
if(score <= 50) {
System.out.println("C Grade");
} else if(score <= 70) {
System.out.println("B Grade");
} else if(score <= 100) {
System.out.println("A Grade");
}
It will print B Grade.
if(score<=50) {
System.out.println("C Grade");
} else {
if(score <= 70) {
System.out.println("B Grade");
}
if(score <= 100) {
System.out.println("A Grade");
}
}
Now, According to you if we follow above approach where conditions are not mutually exclusive. It will print B Grade and A Grade which is not true.
So, in the cases where conditions in if are not mutually exclusive you will run into problems. That's why nesting of if..else is needed.
Related
I am learning java, and i got stuck in a stupid situation.
I could just throw all my code in here, but it would only confuse you even more. So I converted my logical thinking into this:
if (a)
{
*instruction 1*
}
if (!a && b && !c)
{
*instruction 2*
}
if (!a && b && c)
{
*instruction 3*
}
else
{
*instruction 4*
}
All I want to know is if i can simplify this, so i don't use so many "if" statements...
And I'd like to know how you came to your conclusion.
Thanks in advance! (Yes, I'm dumb, help me)
EDIT:
I'm adding a truth-table with every combination of a, b and c:
If a, b and c are local variables or otherwise guaranteed not to change while you go through the if-statements, then you can write your code as:
if (a) {
// instruction 1
} else if (b) {
if (!c) {
// instruction 2
} else {
// instruction 3
}
}
if (a || !b || !c) {
// instruction 4
}
However, it is still pretty complex. Depending on the meaning of a, b and c and how you calculate them, you should probably refactor this code into multiple methods. For example, the if-statement relating to c might fit well into a single-responsibility method.
If you want to verify whether this change is correct, you can create a truth-table with all possible combinations of a, b and c being true or false. You would check which instruction would be performed in your first code, and which instruction gets performed in the new code.
You probably want to use a switch statement to make this more readable.
Something like:
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
The switch statement is a multi-way branch statement. It provides an easy way to dispatch execution to different parts of code based on the value of the expression. Basically, the expression can be byte, short, char, and int primitive data types. Beginning with JDK7, it also works with enumerated types ( Enums in java), the String class and Wrapper classes.
As far as i can see there's a Wrapper Class for Booleans.
boolean result = switch (ternaryBool) {
case TRUE -> true;
case FALSE -> false;
case FILE_NOT_FOUND -> throw new UncheckedIOException(
"This is ridiculous!",
new FileNotFoundException());
// as we'll see in "Exhaustiveness", `default` is not necessary
default -> throw new IllegalArgumentException("Seriously?! 🤬");
};
https://blog.codefx.org/java/switch-expressions/
In multiple conditions, I would use the switch statement to make it easier to read.
https://beginnersbook.com/2017/08/java-switch-case/
I'm a beginner in coding. I was recently working with to create a chatting programme where a user will chat with my computer. Here is a part of the code:
System.out.println("Hello, what's our name? My name is " + answer4);
String a = scanner1.nextLine();
System.out.println("Ok, Hello, " + a + ", how was your day, good or bad?");
String b = scanner2.nextLine();
**if (b.equals("good"))** { //1
System.out.println("Thank goodness");
} else **if (b.equals("it was good"))** { //2
System.out.println("Thank goodness");
} else **if (b.equals("bad"))** { //3
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
} else **if (b.equals("it was bad"))**{ //4
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
}
if(age<18){System.out.println("How was school?");}
else if (age>=18){System.out.println("How was work?");}
The conditions of the if statements are in Bold (surrounded with **). In case of first and the second condition I want my application to do same thing. Similarly third and fourth condition. I thought it was possible to somehow group them in if statement.
I tried with below code but it doesn't compile:
if (b.equals("good"), b.equals("it was good")) {
System.out.println("Thank goodness");
} else if (b.equals("bad"),(b.equals("it was bad"))) {
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
}
Can someone correct it for me?
You can use logical operators to combine your boolean expressions.
&& is a logical and (both conditions need to be true)
|| is a logical or (at least one condition needs to be true)
^ is a xor (exactly one condition needs to be true)
(== compares objects by identity)
For example:
if (firstCondition && (secondCondition || thirdCondition)) {
...
}
There are also bitwise operators:
& is a bitwise and
| is a bitwise or
^ is a xor
They are mainly used when operating with bits and bytes. However there is another difference, let's take again a look at this expression:
firstCondition && (secondCondition || thirdCondition)
If you use the logical operators and firstCondition evaluates to false then Java will not compute the second or third condition as the result of the whole logical expression is already known to be false. However if you use the bitwise operators then Java will not stop and continue computing everything:
firstCondition & (secondCondition | thirdCondition)
Here are some common symbols used in everyday language and their programming analogues:
"," usually refers to "and" in everyday language. Thus, this would translate to the AND operator, &&, in Java.
"/" usually refers to "or" in everyday language. Thus, this would translate to the OR operator, ||, in Java.
"XOR" is simply "x || y but both cannot be true at the same time". This translates to x ^ y in Java.
In your code, you probably meant to use "or" (you just used the incorrect "incorrect solution" :p), so you should use "||" in the second code block for it to become identical to the first code block.
Hope this helped :)
You're looking for the "OR" operator - which is normally represented by a double pipe: ||
if (b.equals("good") || b.equals("it was good")) {
System.out.println("Thank goodness");
} else if (b.equals("bad") || b.equals("it was bad")) {
System.out.println("Why was it bad?");
String c = scanner3.nextLine();
System.out.println("Don't worry, everything will be ok, ok?");
String d= scanner10.nextLine();
}
This is probably more answer than you need at this point. But, as several others already point out, you need the OR operator "||". There are a couple of points that nobody else has mentioned:
1) If (b.equals("good") || b.equals("it was good")) <-- If "b" is null here, you'll get a null pointer exception (NPE). If you are genuinely looking at hard-coded values, like you are here, then you can reverse the comparison. E.g.
if ("good".equals(b) || "it was good".equals(b))
The advantage of doing it this way is that the logic is precisely the same, but you'll never get an NPE, and the logic will work just how you expect.
2) Java uses "short-circuit" testing. Which in lay-terms means that Java stops testing conditions once it's sure of the result, even if all the conditions have not yet been tested. E.g.:
if((b != null) && (b.equals("good") || b.equals("it was good")))
You will not get an NPE in the code above because of short-circuit nature. If "b" is null, Java can be assured that no matter what the results of the next conditions, the answer will always be false. So it doesn't bother performing those tests.
Again, that's probably more information than you're prepared to deal with at this stage, but at some point in the near future the NPE of your test will bite you. :)
You can have two conditions if you use the double bars(||). They mean "Or". That means only ONE of your conditions has to be true for the loop to execute.
Something like this:
if(condition || otherCondition || anotherCondition) {
//code here
If you want all of conditions to be true use &&. This means that ALL conditions must be true in order for the loop to execute. if any one of them is false the loop will not execute.
Something like this:
if(condition && otherCondition && anotherCondition) {
//code here
You can also group conditions, if you want certain pairs of them to be true. something like:
if(condition || (otherCondition && anotherCondition)) {
//code here
There is a simpler way.
if (b.contains("good")) {
...
}
else if (b.contains("bad")) {
...
}
I was wondering if there is any better way to handle n no. of if/else-if block in Java.
I have a situation where I need to print different values based on n no. of if/else-if/conditions blocks like
if(p==1 && q==r)
System.out.println("Condition 1");
else if(r==p && q==9)
System.out.println("Condition 2");
else if(z==1 && s==r)
System.out.println("Condition 3");
else if(p==1 || x==r && y==7)
System.out.println("Condition 4");
else if(q==z && y==r || p==4)
System.out.println("Condition 5");
else if(x==z && r==5 || z==30)
System.out.println("Condition 6");
else if(s==1 || q==x)
System.out.println("Condition 7");
else if(r==14 || q==r++ || z==y)
System.out.println("Condition 8");
else if(q==18 && s==r || p==90)
System.out.println("Condition 9");
else if(y==19 || q==89)
System.out.println("Condition 10");
...
Is there any other way to handle it instead of putting multiple if/else if statements so that if later on any new condition come, it will be easy to handle it.
The real answer here: don't do that.
In good OO design, you solve this problem in very different ways; for example by using polymorphism. You actually want to avoid having many different sources of information, to then make decisions on that.
In your case; I would be thinking towards FSMs and the state pattern for example.
What I mean is: your code is showing a certain "approach" towards solving a problem. And as long as you keep that approach as is, you are only talking about finding ways to express your solution in the "least ugly" way.
Instead, you should step back and look into approaches that can be expressed in "really beautiful" ways.
Thus: there is no "simple" direct answer to your question. You have to step back and have a close look at the requirements you want to fulfill; to then design a better, "more OO" solution to that.
The minimal thing here: you could start by declaring an enum like:
public enum Condition {
A, B, C, ...
and then you would have some factory method that hides all those statements; like:
Condition currentCondition = determineCondition(p, q, r, z);
switch(currentCondition) {
case A:
Meaning: you want to at least "centralize" that knowledge somewhere to avoid code duplication. But again; that is just like putting some new color on an old, rusty car. It helps for the moment, but doesn't really improve things.
Regarding your comments: yes, the switch is only marginally "better" than if elses. But as you said: you can't make too many chances, so at least you want to have exactly one piece of code that determines state.
But in the end: I think you are approaching this on a wrong level. You are probably dealing with some kind of complicated business logic; and you want to solve that on a low level like this. But nothing you do on such a level will lead to a robust, long-term maintainable solution. Probably the real solution is to step back and look into using some kind of workflow engine.
You can make a Condition (interface or superclass) which accepts all your variables:
public interface Condition {
boolean isConditionMet(int p, int q, int r, int s, int x, int y, int z);
void performAction();
}
For each single Condition you can override/implement a boolean method isConditionMet().
public class C1 implements Condition {
public boolean isConditionMet(int p, int q, int r, int s, int x, int y, int z) {
return p == 1 && q == r;
}
public void performAction() {
System.out.println("Condition 1");
}
}
Then you can put all conditions in a collection, and for each Condition you have you can ask:
if (condition.isConditionMet())
condition.performAction();
Now each Condition object itself is responsible for when it should act, and what it should do then. A perfect separation of concerns.
Downvote bait
When you say "if any new condition come" do you mean you are willing to modify the code if a new condition comes, or must the code adapt without being modified? If the former, I think you've done it the best way. (Though, I would add an if (false){} at the top, so all the real cases look the same, making it easy to rearrange them.) If the latter, then a table-driven approach is needed. Performance is not an issue if every case has a print statement. If you do care about performance, then put the most common cases first.
If you care even more about performance, have a tree of if-statements, rather than a ladder. So, for example, have something like this, so you're not repeatedly asking the same sub-question:
if (p == 1){
.. all the cases where p is 1
} else {
.. all the other cases
}
There may be other OO-related ways to write this, but none of them will be faster or easier to modify than this.
int a=10, b=5;
if(a>b)
{
if(b>5)
System.out.println("b is:"+b);
}
else
System.out.println("a is:"+a");
}
This code shows no output when running, why?
Your snippet annotated:
int a=10, b=5;
if(a>b) // is true (10>5)
{
if(b>5) // is false (5>5)
System.out.println("b is:"+b);
// no else case, so does nothing
}
else // never gets here
System.out.println("a is:"+a");
} // unmatched bracket
Make sure there’s no syntax errors in your full code (like unmatched brackets) and that there’s always an else case, be it for development purposes only.
That's dangling else ambiguity. You are matching wrong if clause with the else clause? It's a common error.
This is often due to poor formatting.
That's your code:
int a=10, b=5;
if(a>b)
{
if(b>5)
System.out.println("b is:"+b);
}
else
System.out.println("a is:"+a");
}
That's a properly formatted code:
int a=10, b=5;
if(a>b)
{
if(b>5)
System.out.println("b is:"+b);
}
else
System.out.println("a is:"+a");
}
See how each statement is indented. It's clear that the else clause is associated with the outer if. But, in your code it's hard to see.
Your IDE can properly format the code for you. If you are using Eclipse, for example, you can select your code and press Ctrl + I to format your code.
if(a>b) = true | No output
if(b>5) = false | No output (Reason: 5 is not greater than 5)
else block is not being executed
Your code shows no output because a > b but b = 5, not greater than. To solve this, change if(b>5) to if(b>=5).
This is another case where reformatting makes the question so much clearer.
int a=10, b=5;
if(a>b) { // 'true' - This block is executed
if(b>5) // 5 is not greater than 5, it's equal, so this isn't executed
System.out.println("b is:"+b);
} else { // This is not executed
System.out.println("a is:"+a);
}
When a bug gets confusing just take the program step by step and think as the compiler would. Also, I'd recommend forming a full block with { braces } for an else statement if you used braces for the if statement, it makes things tie together nicer and it's easier to read. Making sure things are indented properly also makes things easier to understand. Readability is important!
int a=10, b=5;
if(a>b)
{
if(b>5)
System.out.println("b is:"+b);
}
else
System.out.println("a is:"+a");}
In your code above In first if you are checking (a>b) i.e (10>5) the condition is true so execution of block inside first if is started.
In your second if condition (b>5) i.e (5>5) condition is false. So it terminates the program hence it doesn't displaying anything.
For better understanding I edit your code as below:
int a=10,b=5;
if(a>b) // This condition is true so this if block executed
{
if(b>5) // this is false so this block won't execute.
{
System.out.println("b is :"+b);
}
}
else // Alredy first if executed because true condition so this also not executing
{
System.out.println("a is :"+a);
}
// Thats why you don't get any output in this program.
If you have code like this:
if (A > X && B > Y)
{
Action1();
}
else if(A > X || B > Y)
{
Action2();
}
With A > X and B > Y, will both parts of the if-else-if ladder be executed?
I'm dealing with Java code where this is present. I normally work in C++, but am an extremely new (and sporadic) programmer in both languages.
No, they won't both execute. It goes in order of how you've written them, and logically this makes sense; Even though the second one reads 'else if', you can still think of it as 'else'.
Consider a typical if/else block:
if(true){
// Blah
} else{
// Blah blah
}
If your first statement is true, you don't even bother looking at what needs to be done in the else case, because it is irrelevant. Similarly, if you have 'if/elseif', you won't waste your time looking at succeeding blocks because the first one is true.
A real world example could be assigning grades. You might try something like this:
if(grade > 90){
// Student gets A
} else if(grade > 80){
// Student gets B
} else if(grade > 70){
// Student gets c
}
If the student got a 99%, all of these conditions are true. However, you're not going to assign the student A, B and C.
That's why order is important. If I executed this code, and put the B block before the A block, you would assign that same student with a B instead of an A, because the A block wouldn't be executed.
If both A > X and B > Y are true then your code will only execute Action1. If one of the conditions is true it will execute Action2. If none are true, it will do nothing.
Using this:
if (A > X || B > Y) {
Action2
if (A > X && B > Y) {
Action1
}
}
will result in the possibility of both actions occurring when A > X and B > Y are both true.
If you're talking about C, then only the first block that satisfies the condition is executed - after the control "enters" the conditional block it then "leaves" after all other conditions.
If you want such behavior, then just use two separate conditions - remove "else" and you have it.
When the condition after if is true, only the first block is executed. The else block is only executed when the condition is false. It doesn't matter what's in the else block, it's not executed. The fact that the else block is another if statement is irrelevant; it won't be executed, so it will never perform the (A > X || B > X) test, and its body will not be executed even if that condition is true.