Java If and Else Statements
The dangling else problem occurs when nested if statements are interpreted differently by the compiler than the programmer intended.
A Nested If That Prints Nothing
Nested if statements are common in Java, and an else added to a nested structure is one of the places where a program can quietly do something its author did not intend. The source for this lesson describes the problem as the dangling else problem: nested if statements are interpreted differently by the compiler than the programmer intended. Nothing in the program signals an error, so the mismatch is easy to miss.
What do you think happens?
Given x = -1 and y = 5, and the unbraced version of the nested if with an else below, what does the program print?
Reveal answer
Nothing is printed
Without a block, the else is read as belonging to the nearest if that can take it, which is the inner condition y greater than zero. The outer condition x greater than zero is false, so the inner if is never reached and the else attached to it never runs. The program therefore prints nothing. The programmer who wrote the code most likely expected B to print, because the else looks like it belongs to the outer if.
What the Programmer Expects the Else to Do
When one if statement sits inside another and an else is added, it is natural to believe the else belongs to the outer condition. The indentation seems to say so: the inner if is pushed to the right under the outer if, and the else lines up with the outer if. The source notes that many beginners assume a program will run exactly the way its indentation suggests.
The compiler does not treat indentation as a rule. It builds a structure from the code, and that structure can differ from the one the programmer had in mind. The gap between intended meaning and the meaning the compiler actually uses is the core of the dangling else problem. The problem appears when nested if statements are written without enough structure to show which if an else is meant to pair with.
Tracing the Unbraced Version
The two versions below use the same two conditions and the same two print statements. The first version places the inner if directly under the outer if with no block. Read it the way the compiler does: the outer if controls only the single statement immediately after it, which is the inner if. The else that follows is then read against the nearest if that can take it, so it pairs with the inner condition y greater than zero.
int x = -1;
int y = 5;
if (x > 0)
if (y > 0)
System.out.println("A");
else
System.out.println("B");- 1Line 1 sets x to -1, so the outer condition will be false.
- 2Line 2 sets y to 5. This value would make the inner condition true, but the inner condition is never evaluated.
- 3The outer if tests x greater than zero. The test fails.
- 4Because the outer condition is false, the statement controlled by the outer if is skipped, and that statement is the inner if.
- 5The else is paired with the inner if, so it is also skipped. The program prints nothing.
- The outer condition x greater than zero is false for x = -1.
- The inner if is the only statement the outer if controls, so it is never reached.
- The else is read against the inner if, so it does not run when the outer condition is false.
(no output)Which If the Else Attaches To
The unbraced form has a meaning in which the outer if has no else at all. The else is attached to the inner if, so the outer if on its own has only the single statement it controls. The hierarchy below makes this containment visible. Read it from the top: the outer condition contains the inner condition, and the else sits on the inner condition's branch structure.
In this structure the else is a branch of the inner if, not of the outer one. The outer if does not have an else. That is why the output for x = -1 is empty even though the else is written at the same indentation level as the outer if.
Forcing Structure with Braces
Adding a block changes the grouping. Curly braces enclose the inner if so that it becomes one unit inside the outer if. The else that follows the closing brace can no longer attach to the inner statement, so it pairs with the outer condition. The source gives this as the fix: enclosing the nested if in a block forces the other interpretation, which is the reading the programmer usually intends.
B- The braces group the inner if into a single unit inside the outer if.
- The else follows the closing brace, so it is paired with the outer condition x greater than zero.
- For x = -1 the outer condition is false, so the else runs and B is printed.
if (x > 0)
if (y > 0)
System.out.println("A");
else
System.out.println("B");No block: the else pairs with the inner if, and nothing prints when x is -1.
if (x > 0) {
if (y > 0)
System.out.println("A");
} else
System.out.println("B");Block added: the else pairs with the outer if, and B prints when x is -1.
Mistakes Programmers Make with Nested Conditions
The following mistakes come up often when programmers write nested conditions. Each one involves trusting the layout of the code rather than its grouping.
Common mistake Trusting indentation to show which if an else belongs to
What it looks likeif (x > 0) if (y > 0) System.out.println("A"); else System.out.println("B");Why it failsThe else is indented under the outer if, but the compiler pairs it with the inner if when no block is present.
Do this insteadAdd curly braces around the inner if whenever an else is meant to belong to the outer condition.
Common mistake Assuming the else runs whenever the outer condition is false
Why it failsIn the unbraced form the else is attached to the inner condition, so it is skipped when the outer condition is false.
Do this insteadWhen behavior is unexpected, check the case where the outer condition is false and identify which if the else is attached to.
Common mistake Testing only the cases that look correct on the page
Why it failsThe two versions give different results only in the case where x is less than or equal to zero, so a test with a positive x will not reveal the problem.
Do this insteadInclude a value of x that makes the outer condition false when testing nested conditionals.
Locating Where Intent and Execution Diverge
When a nested conditional produces an unexpected result, the most useful question is where the program's behavior first departs from the plan. The flowchart below follows the unbraced version for x = -1. The programmer's plan is shown as the path that prints B. The path the compiler actually follows ends with nothing printed, because the else sits under the inner decision.
Finding the divergence in the unbraced version
The unbraced code with x = -1 and y = 5 prints nothing, but the programmer expected B. Where does the path diverge?
- 1List the conditions
The outer condition is x greater than zero. The inner condition is y greater than zero. There is one else.
- 2Identify the pairing
Without a block, the else is read as belonging to the nearest if that can take it, which is the inner if.
- 3Check the outer false case
With x = -1 the outer condition is false, so the inner if is never reached.
- 4Locate the divergence
The path departs from the plan at the outer decision. The plan expected the no branch to reach B, but the else is attached inside the yes branch, so the no branch reaches nothing.
The divergence happens at the outer condition's no branch. The else the programmer expected to run is attached to the inner if, so nothing is printed.
Practice Tracing the Pairing
Consider this unbraced code: if (x > 0) if (y > 0) System.out.println("A"); else System.out.println("B"); Trace the program for x = -2 and y = 3. Say which if the else pairs with, what the program prints, and what the programmer most likely intended. Then add braces so the else pairs with the outer if, and state the new output for the same values.
Hints
- Ask which if the else attaches to in the code as written, not in the layout you expect.
- For x = -2 the outer condition is false. Check whether the inner if is ever reached.
- After adding braces, the else follows the closing brace of the outer if.
Key Takeaways
- The dangling else problem occurs when nested if statements are interpreted differently by the compiler than the programmer intended.
- Without a block, an else is read against the nearest if that can take it, so in a nested if it pairs with the inner condition.
- Enclosing the inner if in curly braces makes it one unit inside the outer if, so the else pairs with the outer condition.
- When behavior is unexpected, check the case where the outer condition is false and identify which if the else is attached to.