2.1 Conditional Logic: if-else and Ternary Operators

Key Takeaways

  • Java if conditions require boolean expressions; assignments like if (x = 5) fail to compile for non-boolean types, while boolean assignments like if (b = true) assign and evaluate to true.
  • The dangling else problem is resolved by binding each else clause to the closest preceding unmatched if statement within the same block scope.
  • Short-circuit operators (&&, ||) skip evaluation of the right operand once the outcome is determined, unlike eager bitwise/logical operators (&, |, ^) which always evaluate both operands.
  • Ternary expressions (condition ? expr1 : expr2) apply binary numeric promotion across branches and trigger runtime NullPointerExceptions if unboxing occurs on a null reference.
Last updated: September 2026

Decision Making with if-else and Ternary Operators

Conditional decision making forms the backbone of control flow in Java. For the Oracle Certified Professional: Java SE 21 Developer (1Z0-830) exam, questions test not merely basic branching, but subtle language grammar rules, short-circuit evaluation side effects, the dangling else problem, variable scoping quirks, and type resolution mechanics in ternary expressions.


1. The if and if-else Statement Grammar

Boolean Condition Strictness

In Java, the condition inside if (...) must strictly evaluate to a boolean primitive or a java.lang.Boolean object (which undergoes automatic unboxing). Unlike C, C++, or JavaScript, Java does not treat integers, non-null object references, or non-empty strings as truthy values.

  • if (1) -> Compilation Error: incompatible types: int cannot be converted to boolean.
  • if (null) -> Compilation Error: incompatible types: <nulltype> cannot be converted to boolean.
  • Boolean b = null; if (b) -> Compiles cleanly, but throws a NullPointerException at runtime due to the automatic unboxing call b.booleanValue().

The Assignment vs. Equality Trap

A classic certification trap involves confusing the assignment operator (=) with the equality operator (==) inside an if condition:

boolean isAvailable = false;
if (isAvailable = true) { // Assigns true to isAvailable, and evaluates to true!
    System.out.println("Available"); // Executes!
}

int score = 0;
// if (score = 100) { } // COMPILATION ERROR: score = 100 evaluates to int (100), not boolean

When evaluating a boolean variable, if (isAvailable = true) reassigns isAvailable and evaluates the expression result to true, causing the branch to execute. With non-boolean primitive types, the assignment expression evaluates to the assigned value (such as an int), which the compiler rejects immediately because int cannot be converted to boolean.

Solitary Statements and Variable Scope

In Java, a local variable declaration cannot be a solitary statement directly following an if, else, while, or for statement without enclosing curly braces {}:

int score = 95;
if (score > 90)
    int grade = 1; // COMPILATION ERROR: variable declaration not allowed here

// Legal syntax requires explicit block braces:
if (score > 90) {
    int grade = 1; // Legal: scoped to this block
}

The Java Language Specification (JLS §14.9) prohibits declarations directly inside unblocked branches because a local variable declared without a block would immediately go out of scope on the very next line, rendering it completely inaccessible and logically useless.


2. The Dangling else Problem and Resolution

When if-else statements are nested without curly braces, Java resolves ambiguities using the dangling else rule: an else clause always pairs with the nearest preceding unmatched if statement within the same block level, regardless of how the code is indented.

Consider the following snippet:

int x = 5;
int y = 15;

if (x > 10)
    if (y > 10)
        System.out.println("A");
else
    System.out.println("B");

Although the visual indentation suggests that else belongs to if (x > 10), the compiler associates the else with the nearest inner if (y > 10).

Step-by-Step Execution Trace:

  1. x > 10 evaluates to 5 > 10 which is false.
  2. The outer if condition fails, skipping the entire sub-statement (which consists of if (y > 10) System.out.println("A"); else System.out.println("B");).
  3. Nothing is printed to the console!

To make else bind to the outer if, explicit block braces {} are mandatory:

if (x > 10) {
    if (y > 10) {
        System.out.println("A");
    }
} else {
    System.out.println("B"); // Prints "B" because x <= 10
}

3. Short-Circuit vs. Eager Evaluation and Side Effects

Java provides both short-circuit logical operators (&&, ||) and eager bitwise/logical operators (&, |, ^):

OperatorTypeEvaluation BehaviorSide Effect Implication
&&Conditional ANDEvaluates right operand only if left operand is true.Skips right-hand side effects if left is false.
``Conditional OR
&Logical AND (Eager)Always evaluates both operands.Right-hand side effects always execute.
``Logical OR (Eager)Always evaluates both operands.
^Logical XOR (Eager)Always evaluates both operands.true if exactly one operand is true.

Side Effect Consequences in Exam Questions

When expressions containing side effects (such as post-increments x++, pre-increments ++x, or method calls) appear in the right-hand operand, short-circuiting will suppress them:

int a = 10;
int b = 20;

if (a > 15 && ++b > 20) {
    System.out.println("Branch executed");
}
System.out.println("b = " + b); // Prints "b = 20" because ++b was never evaluated!

if (a > 15 & ++b > 20) {
    System.out.println("Branch executed");
}
System.out.println("b = " + b); // Prints "b = 21" because eager & evaluated ++b!

4. The Ternary Conditional Operator (? :)

The ternary operator is Java's only three-operand operator. It provides a compact expression-oriented alternative to simple if-else blocks: booleanExpression ? expression1 : expression2

Expression vs. Statement Rules

The ternary construct is an expression, not a statement. It evaluates to a single value that must be assigned to a variable, passed as a method argument, or returned from a method. It cannot stand alone as an independent executable statement:

int x = 10;
// x > 5 ? System.out.println("Big") : System.out.println("Small"); // COMPILATION ERROR! Not a statement

// Valid usage:
System.out.println(x > 5 ? "Big" : "Small");

Precedence and Right-Associativity

The ternary operator has low precedence (just above assignment operators) and is right-associative. This means nested ternary expressions evaluate from right to left:

int score = 85;
String result = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F";

// Grouped by compiler as:
// score >= 90 ? "A" : (score >= 80 ? "B" : (score >= 70 ? "C" : "F"))

Type Promotion and Result Type Resolution (JLS §15.25)

The compiler determines the result type of a ternary expression at compile time based on the types of the second and third operands:

  1. Identical Types: If both operands are of type T, the result is of type T.
  2. Numeric Widening Promotion: If one operand is int and the other is double, the entire expression type is double. The int value is widened to double:
    int count = 5;
    double price = true ? count : 10.5; // Result is 5.0 (double)
    
  3. Constant Narrowing for Integral Types: If one operand is byte, short, or char and the other is a constant int expression whose value fits into that type, the result type narrows to the smaller type:
    byte b1 = true ? 120 : (byte) 200; // Legal: 120 fits in byte range (-128 to 127)
    
  4. Boxing and Unboxing Pitfalls: When mixing a primitive type with a wrapper object, the wrapper object is unboxed. If the wrapper reference is null, an unexpected NullPointerException occurs at runtime—even if the branch returning null was not the active branch if unboxing is triggered:
    Integer boxedNull = null;
    Double result = true ? 1.0 : boxedNull; 
    // Second operand is Integer, first is primitive double (1.0).
    // Numeric promotion converts both to primitive double, triggering boxedNull.intValue() unboxing!
    
    boolean flag = false;
    double val = flag ? 10.0 : boxedNull; // Throws NullPointerException at runtime!
    

5. Summary of Key Exam Traps for if-else and Ternary

ScenarioCode ExampleOutcome / Exam Trap
Boolean Assignmentif (flag = false)Assigns false, evaluates to false, else branch executes.
Semicolon Stunnerif (x > 5); { doWork(); }Semicolon terminates if-statement with an empty body; { doWork(); } always runs.
Solitary Declarationif (x > 0) int y = 10;Compilation error: variable declaration cannot be solitary sub-statement.
Dangling ElseUnbracketed nested if followed by elseelse binds to the closest inner if, not the outer if.
Ternary Standaloneflag ? foo() : bar();Compilation error if method returns void or is used as standalone statement.
Ternary Null Unboxingint val = flag ? 1 : (Integer) null;Throws NullPointerException when flag is false during unboxing.
Dead Code in ifif (false) { x = 1; }Legal in Java (unlike while(false) which causes an unreachable code compile error).
Loading diagram...
Conditional Evaluation & Dangling Else Resolution
Test Your Knowledge

Given the following Java code snippet, what is the printed output?

int x = 5;
int y = 10;
if (x++ > 5)
    if (++y > 10)
        System.out.print("A");
else
    System.out.print("B");
System.out.print(" x=" + x + " y=" + y);

A
B
C
D
Test Your Knowledge

What is the result of attempting to compile and execute the following code snippet?

Integer a = null;
Double b = 4.0;
double result = true ? a : b;
System.out.println(result);

A
B
C
D
Test Your Knowledge

Which of the following code fragments fails to compile?

A
B
C
D
Test Your Knowledge

What is the output of the following code snippet?

int p = 2;
int q = 3;
if ((p++ > 2) & (++q > 3)) {
    p += 10;
}
if ((p > 2) || (++q > 4)) {
    q += 10;
}
System.out.println("p=" + p + ", q=" + q);

A
B
C
D