Concepts / Java If and Else Statements

Java If and Else Statements

The dangling else problem occurs when nested if statements are interpreted differently by the compiler than the programmer intended.

  • Programming

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?

  • A

  • B

  • Nothing is printed

  • Both A and B are printed

Reveal answer
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.

Code walkthrough
int x = -1;
int y = 5;

if (x > 0)
    if (y > 0)
        System.out.println("A");
else
    System.out.println("B");
  1. 1
    Line 1 sets x to -1, so the outer condition will be false.
  2. 2
    Line 2 sets y to 5. This value would make the inner condition true, but the inner condition is never evaluated.
  3. 3
    The outer if tests x greater than zero. The test fails.
  4. 4
    Because the outer condition is false, the statement controlled by the outer if is skipped, and that statement is the inner if.
  5. 5
    The 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.
Output
(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.

if (x > 0)outer conditionif (y > 0)inner condition, gets theelseprint Atrue branch of inner ifprint Belse branch of inner ifcontainsthenelse
Which if does the else attach to when no braces are used, and how does the nesting look once the compiler pairs it?

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.

java
Output
B
Notes on the code
  • 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.
Before
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.

After
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.

else pairs withinner ifno bracesno outputwhen x is -1else pairs withouter ifbraces addedprint Bwhen x is -1leads toleads to
How does adding braces change the block boundaries, and what does the else pair with after the braces are added?

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 like
    if (x > 0)
        if (y > 0)
            System.out.println("A");
    else
        System.out.println("B");
    Why it fails

    The else is indented under the outer if, but the compiler pairs it with the inner if when no block is present.

    Do this instead

    Add 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 fails

    In the unbraced form the else is attached to the inner condition, so it is skipped when the outer condition is false.

    Do this instead

    When 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 fails

    The 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 instead

    Include 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.

x > 0?outer conditiony > 0?inner conditionprint Aprint Belse of inner ifnothing printedactual path for x = -1yesnoyesno
For x equal to -1, which branches run under the compiler's pairing, and where does that path differ from the intended path?
Worked example

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?

  1. 1
    List the conditions

    The outer condition is x greater than zero. The inner condition is y greater than zero. There is one else.

  2. 2
    Identify the pairing

    Without a block, the else is read as belonging to the nearest if that can take it, which is the inner if.

  3. 3
    Check the outer false case

    With x = -1 the outer condition is false, so the inner if is never reached.

  4. 4
    Locate 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.

Result

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

MEDIUM

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.