5.1 While and Do-While Loops

Key Takeaways

  • The while loop is a pre-test repetition construct that evaluates its controlling boolean condition before executing the loop body, allowing for a minimum iteration count of zero.
  • The do-while loop is a post-test repetition construct that executes its body first before evaluating the condition, guaranteeing at least one execution regardless of the condition.
  • A do-while statement strictly requires a terminating semicolon after its condition header: do { ... } while (condition);.
  • Java enforces compile-time reachability analysis; while (false) causes a fatal 'unreachable statement' compilation error, whereas do { ... } while (false); and non-final variables like boolean b = false; while (b) compile cleanly.
  • Infinite loops occur when loop control variables are not updated inside the body, when termination conditions are mathematically unreachable, or when floating-point precision issues prevent exact equality comparisons.
Last updated: September 2026

5.1 While and Do-While Loops

[!NOTE] Exam Focus: Oracle's "Using Looping Statements" topic area lists six objectives, including "use a while loop", "use a do-while loop", and "compare and contrast the for, while, and do-while loops". Candidates are extensively tested on the critical operational differences between pre-test and post-test condition evaluation, compiler reachability rules (such as while(false) compilation failures), syntax mandates (such as the trailing semicolon on do-while), and code-tracing scenarios involving loop counters and infinite loop traps.

In computer programming, control flow structures direct the order in which statements are executed. While decision-making constructs like if-else and switch execute a block of code at most once, repetition control structures—known as loops—allow a sequence of statements to execute repeatedly based on a boolean condition. In Java, repetition constructs are divided into two fundamental categories:

  1. Counter-Driven Loops: Loops typically utilized when the total number of iterations is known before entering the loop (such as the standard for loop).
  2. Condition-Driven Loops: Loops utilized when the number of iterations is indeterminate and depends on dynamic runtime conditions (such as reading user input until a sentinel value is received, polling an I/O stream, or iterating until a mathematical threshold is crossed).

Java provides two foundational condition-driven looping statements: the while loop and the do-while loop.


The while Loop: Pre-Test Iteration Architecture

The while loop is a pre-test loop (also referred to as a pre-condition loop). It evaluates its controlling boolean expression before each attempted execution of the loop body.

Formal Syntax

while (booleanCondition) {
    // Loop body: statements executed repeatedly as long as booleanCondition evaluates to true
}

The booleanCondition must evaluate strictly to a primitive boolean or a boxed Boolean object (which Java automatically unboxes). Passing an integer, a string, or a reference object directly into the condition produces an immediate compile-time error (incompatible types: int cannot be converted to boolean).

Execution Lifecycle and Zero-Iteration Capability

Because the condition check occurs prior to executing any statements in the body, the body of a while loop may execute zero times if the condition evaluates to false upon initial entry:

int sensorReading = 150;
int threshold = 100;

// Pre-test evaluation: 150 < 100 evaluates to false immediately
while (sensorReading < threshold) {
    System.out.println("Reading is below threshold. Adjusting...");
    sensorReading += 10;
}
System.out.println("Monitoring resumed. Final reading: " + sensorReading);
// Output:
// Monitoring resumed. Final reading: 150

In this example, the statements inside the curly braces are completely bypassed, and execution immediately transfers to the first statement following the loop's closing brace.

Variable Management and Scope in while Loops

Unlike standard for loops, the while construct provides no built-in header mechanism for declaring loop control variables. Therefore, managing loop counters involves three separate stages:

  1. Initialization: Declaring and initializing the loop control variable outside and prior to the while statement.
  2. Evaluation: Testing the variable within the while header condition.
  3. Modification: Explicitly updating the variable inside the loop body.
int count = 1; // 1. Initialization (Scope: entire enclosing block)

while (count <= 3) { // 2. Pre-test evaluation
    System.out.println("Processing item: " + count); // Loop body statement
    count++; // 3. Modification (Advancement toward termination)
}

// Variable remains in scope and accessible after loop termination!
System.out.println("Final count value: " + count); // Prints: Final count value: 4

[!IMPORTANT] Variable Scope Distinction: Because count is declared outside the loop header, its scope persists after the loop terminates. When the condition count <= 3 fails, count holds the value 4. This differs from a standard for loop where a variable declared in the header ceases to exist upon loop exit.

Conversely, any local variable declared inside the body of a while loop is re-created and destroyed on every iteration, and is completely inaccessible outside the loop:

while (count < 5) {
    int tempResult = count * 10; // Allocated in the current iteration's scope
    System.out.println(tempResult);
    count++;
} // tempResult is destroyed here

// System.out.println(tempResult); // COMPILE ERROR: cannot find symbol variable tempResult

The do-while Loop: Post-Test Iteration Architecture

The do-while loop is a post-test loop (also known as a post-condition loop). It executes its body statements first, and evaluates the controlling boolean condition after each execution of the body.

Formal Syntax

do {
    // Loop body: executes at least once
} while (booleanCondition); // MANDATORY TERMINATING SEMICOLON!

Guaranteed Single Execution

Because the condition evaluation occurs at the very bottom of the construct, the body of a do-while loop is guaranteed to execute at least once, regardless of whether the controlling condition initially evaluates to true or false:

int attempts = 5;
int maxAttempts = 3;

do {
    System.out.println("Attempting system handshake... Current count: " + attempts);
    attempts++;
} while (attempts < maxAttempts);

System.out.println("Handshake routine complete. Final attempts: " + attempts);

Console Output:

Attempting system handshake... Current count: 5
Handshake routine complete. Final attempts: 6

Even though the condition attempts < maxAttempts (6 < 3) is immediately false, the body executes once, printing the message and incrementing attempts to 6 before the loop terminates.

Typical Use Cases for do-while Loops

A do-while loop is the natural choice when an action must occur before determining whether repetition is necessary:

  • Interactive Console Menus: Displaying options to a user and reading their response before checking whether the response was valid or if the user chose to exit.
  • Input Validation: Prompting a user to enter a password or numeric value at least once, repeating only if the input fails validation checks.
  • Network Connection Handshakes: Sending an initial communication packet and waiting for an acknowledgment before testing retry counters.

Mandatory Syntax Rules and The Semicolon Pitfall

One of the most frequent syntax-related questions on the 1Z0-811 examination concerns the placement of semicolons in loop headers.

1. The Mandatory Trailing Semicolon on do-while

In Java grammar, a do-while statement requires a closing semicolon immediately following the condition parentheses: while (condition);. Omitting this semicolon triggers an immediate compile-time error:

// COMPILE ERROR: ';' expected
int k = 0;
do {
    k++;
} while (k < 5) // Missing semicolon causes compilation failure!

2. The Accidental Semicolon on while (The Empty Body Trap)

Conversely, placing a semicolon immediately after the header of a while loop is syntactically valid in Java, but creates an empty statement (null statement) as the entire loop body:

int n = 0;
while (n < 5); // TRAP: The semicolon constitutes the entire loop body!
{
    System.out.println("n = " + n); // This block is outside the loop!
    n++;
}

What Happens at Runtime?

  1. The JVM evaluates n < 5 (0 < 5), which is true.
  2. The JVM executes the empty body (the semicolon ;), doing nothing.
  3. Because n was never updated inside the empty body, n remains 0.
  4. The JVM re-evaluates 0 < 5, which is still true.
  5. The program enters an unbreakable infinite loop and will hang indefinitely without ever reaching the indented block below it!

Architectural Comparison: while vs. do-while

The key differences between Java's two condition-driven loops are contrasted in the table below:

Technical Attributewhile Loopdo-while Loop
Evaluation TimingPre-test: Condition evaluated before the body executesPost-test: Condition evaluated after the body executes
Minimum Iteration Count0 (body can be completely skipped)1 (body always executes at least once)
Header SemicolonNo semicolon after while(cond) (causes empty body bug)Mandatory semicolon after while(cond);
Loop Control ScopeDeclared before loop; remains in scope after terminationDeclared before loop; remains in scope after termination
Condition ExpressionMust evaluate to primitive boolean or boxed BooleanMust evaluate to primitive boolean or boxed Boolean
Primary Use CasesReading files, iterating collections, event-driven loopsUser menu prompts, password prompts, retry loops

Compile-Time Reachability Analysis (JLS §14.21)

The Java compiler incorporates strict static control-flow analysis known as reachability analysis. Java enforces that every statement in a program must be reachable under normal execution paths. If the compiler can deduce at compile time that a statement can never possibly be reached, it generates a fatal compile-time error.

1. The while (false) Compilation Error

When the boolean literal false is hardcoded directly into a while loop condition, the compiler knows with absolute certainty that the body statements can never execute under any circumstances. Therefore, Java rejects the code:

// COMPILE ERROR: unreachable statement
while (false) {
    System.out.println("This statement can never execute");
}

2. Compile-Time Constants vs. Non-Final Variables

Why does while (false) fail to compile, while checking a variable initialized to false compiles cleanly?

  • Non-Final Variables (Reachable at Compile Time):

    boolean running = false;
    while (running) { // LEGAL: Compiles successfully!
        System.out.println("Body");
    }
    

    Because running is a non-final variable, the Java compiler treats it as mutable. The compiler does not track variable mutation across statements during static reachability analysis. At runtime, the loop simply executes zero times.

  • Compile-Time Constant Expressions (Unreachable):

    final boolean RUNNING = false; // Compile-time constant
    // COMPILE ERROR: unreachable statement
    while (RUNNING) {
        System.out.println("Body");
    }
    

    Because RUNNING is declared final and initialized with a literal constant, the compiler performs constant inlining. The expression while (RUNNING) is replaced at compile time with while (false), triggering the unreachable statement compilation error.

3. The do-while (false) Exception

A do-while loop executes its body before checking the condition. Therefore, the statements in the body are completely reachable! Consequently, writing do { ... } while (false); is 100% valid, legal Java syntax that compiles cleanly and executes exactly once:

do {
    System.out.println("This compiles and executes exactly once!");
} while (false); // LEGAL: Compiles and executes 1 time

4. Statements Following Infinite Loops

If a while loop condition is an unyielding compile-time constant true (such as while (true)), and the body contains no break or return statement that could exit the loop, the compiler determines that the loop can never terminate. Any statement placed immediately following the loop is rejected as unreachable:

while (true) {
    System.out.println("Service daemon running...");
}
// COMPILE ERROR: unreachable statement
System.out.println("Service stopped");

Infinite Loops: Root Causes, Patterns, and Hazards

An infinite loop is a sequence of instructions that repeats endlessly because its terminating condition is never met. While infinite loops are sometimes created intentionally (e.g., in server listeners or operating system background daemons, accompanied by explicit break or return exits), unintended infinite loops cause applications to freeze, spike CPU utilization to 100%, and exhaust system resources.

1. Omission of Loop Counter Update

The most common cause of unintentional infinite loops is forgetting to modify the loop control variable within the loop body:

int index = 0;
while (index < 5) {
    System.out.println("Current index: " + index);
    // TRAP: index++ is forgotten! index remains 0 forever.
}

2. Inverting the Update Direction

Applying the wrong arithmetic operator to the counter causes the variable to move away from the termination condition rather than toward it:

int count = 10;
while (count > 0) {
    System.out.println("Count: " + count);
    count++; // TRAP: count is incremented instead of decremented!
}

Note on Integer Overflow: In Java, signed 32-bit int values overflow at 2,147,483,647 (Integer.MAX_VALUE). After reaching the maximum value, count++ wraps around to -2,147,483,648, at which point count > 0 becomes false and the loop finally terminates after over 2 billion iterations! However, if the condition had been count != 0, the loop would continue indefinitely.

3. Floating-Point Precision Hazards

Comparing floating-point primitives (float and double) using exact equality operators (== or !=) in loop conditions is a hazardous antipattern due to binary floating-point rounding errors (IEEE 754 standard):

double balance = 0.0;
// TRAP: In binary floating point, 0.1 cannot be represented with exact precision
while (balance != 1.0) {
    System.out.println("Balance: " + balance);
    balance += 0.1;
}

Because 0.1 has a repeating fractional component in binary, adding 0.1 ten times results in 0.9999999999999999, which is not equal to 1.0. The variable skips past 1.0 and becomes 1.0999999999999999, causing the loop to run infinitely! To prevent this, always use relational boundary operators (<, <=) or an epsilon threshold when working with floating-point variables.

Loading diagram...
Control Flow Architecture: while (Pre-Test) vs. do-while (Post-Test)
Test Your Knowledge

What is the output of the following Java program?

int x = 5;
do {
    x += 3;
    if (x < 10) {
        x += 1;
    }
} while (x < 10);
System.out.println(x);

A
B
C
D
Test Your Knowledge

Consider the following four code fragments involving loop conditions and reachability analysis in Java SE 8: Fragment 1:

while (false) {
    System.out.println("A");
}
Fragment 2:
final boolean DEBUG = false;
while (DEBUG) {
    System.out.println("B");
}
Fragment 3:
boolean active = false;
while (active) {
    System.out.println("C");
}
Fragment 4:
do {
    System.out.println("D");
} while (false);
Which of these fragments will fail compilation due to an 'unreachable statement' error?

A
B
C
D
Test Your Knowledge

What is printed to the console upon executing the following Java code snippet?

int count = 0;
int sum = 0;
while (++count <= 3) {
    sum += count;
}
System.out.println("count=" + count + ", sum=" + sum);

A
B
C
D