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.
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 ondo-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:
- Counter-Driven Loops: Loops typically utilized when the total number of iterations is known before entering the loop (such as the standard
forloop). - 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:
- Initialization: Declaring and initializing the loop control variable outside and prior to the
whilestatement. - Evaluation: Testing the variable within the
whileheader condition. - 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
countis declared outside the loop header, its scope persists after the loop terminates. When the conditioncount <= 3fails,countholds the value4. This differs from a standardforloop 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?
- The JVM evaluates
n < 5(0 < 5), which istrue. - The JVM executes the empty body (the semicolon
;), doing nothing. - Because
nwas never updated inside the empty body,nremains0. - The JVM re-evaluates
0 < 5, which is stilltrue. - 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 Attribute | while Loop | do-while Loop |
|---|---|---|
| Evaluation Timing | Pre-test: Condition evaluated before the body executes | Post-test: Condition evaluated after the body executes |
| Minimum Iteration Count | 0 (body can be completely skipped) | 1 (body always executes at least once) |
| Header Semicolon | No semicolon after while(cond) (causes empty body bug) | Mandatory semicolon after while(cond); |
| Loop Control Scope | Declared before loop; remains in scope after termination | Declared before loop; remains in scope after termination |
| Condition Expression | Must evaluate to primitive boolean or boxed Boolean | Must evaluate to primitive boolean or boxed Boolean |
| Primary Use Cases | Reading files, iterating collections, event-driven loops | User 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
runningis 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
RUNNINGis declaredfinaland initialized with a literal constant, the compiler performs constant inlining. The expressionwhile (RUNNING)is replaced at compile time withwhile (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.
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);
Consider the following four code fragments involving loop conditions and reachability analysis in Java SE 8:
Fragment 1:
Fragment 2:
while (false) {
System.out.println("A");
}
Fragment 3:
final boolean DEBUG = false;
while (DEBUG) {
System.out.println("B");
}
Fragment 4:
boolean active = false;
while (active) {
System.out.println("C");
}
Which of these fragments will fail compilation due to an 'unreachable statement' error?do {
System.out.println("D");
} while (false);
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);