☕ Java
while Loop
The while loop is a condition-controlled loop — it continues executing as long as its boolean condition remains true, without specifying in advance how many iterations will occur. It is the natural choice for reading input until end-of-stream, polling until a condition changes, retrying an operation, or any scenario where the termination condition depends on data or events that cannot be predetermined. This entry covers syntax, execution flow, common patterns, infinite loops with controlled exit, and the differences between while and for.
Syntax and Execution Flow
The while loop header contains only a boolean condition. Before every iteration — including the very first — the condition is evaluated. If it is true, the body executes; if it is false, the loop exits and execution continues after the closing brace. Because the condition is checked before the first execution, a while loop may execute its body zero times. This is the key distinction between while and do-while: while is a pre-test loop, do-while is a post-test loop.
The loop variable (or variables) that the condition depends on must be initialised before the loop, and must be updated inside the body, otherwise the condition never changes and the loop runs forever. Forgetting to update the loop variable is the most common source of infinite loops.
Java
// ── Basic while loop ─────────────────────────────────────────────────
int count = 0;
while (count < 5) {
System.out.println("Count: " + count);
count++; // ← MUST update — otherwise infinite loop
}
// Output: 0 1 2 3 4
// ── Execution order ───────────────────────────────────────────────────
// 1. Evaluate condition (count < 5)
// 2. If true → execute body, then back to step 1
// 3. If false → exit loop
// ── Condition false from the start — zero iterations ─────────────────
int n = 10;
while (n < 5) {
System.out.println("Never printed");
}
// Body executes 0 times — this is valid, expected behaviour
// ── Variable must be declared OUTSIDE the loop ────────────────────────
// (unlike for loop which can declare in the header)
int i = 0;
while (i < 10) {
System.out.print(i + " ");
i += 2; // step by 2
}
// Output: 0 2 4 6 8
// ── While loop equivalent to for loop ────────────────────────────────
// These two are exactly equivalent:
// for version:
for (int x = 0; x < 5; x++) {
System.out.println(x);
}
// while version:
int x = 0; // initialisation (before loop)
while (x < 5) {
System.out.println(x);
x++; // update (inside body)
}
// Rule of thumb:
// Use for → when iteration count is known before the loop
// Use while → when termination depends on a condition that changes
// during executionCondition-Controlled Patterns
The most important use of while loops is processing an unknown amount of data — reading lines from a file, consuming events from a queue, or processing digits of a number. The condition expresses what "there is more work to do" means for the specific problem. When the data runs out or the goal is achieved, the condition becomes false and the loop exits naturally.
Another classic pattern is the sentinel-controlled loop, where a special sentinel value signals the end of input. The loop reads values and continues as long as the current value is not the sentinel. This pattern is common in user input processing and stream reading.
Java
// ── Pattern 1: Process digits of a number ────────────────────────────
int number = 12345;
int digitSum = 0;
while (number > 0) {
digitSum += number % 10; // extract last digit
number /= 10; // remove last digit
}
System.out.println("Digit sum: " + digitSum); // 15
// ── Pattern 2: Binary representation ─────────────────────────────────
int value = 42;
StringBuilder binary = new StringBuilder();
while (value > 0) {
binary.insert(0, value % 2); // prepend bit
value /= 2;
}
System.out.println("Binary: " + binary); // 101010
// ── Pattern 3: GCD (Euclidean algorithm) ─────────────────────────────
int a = 48, b = 18;
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
System.out.println("GCD: " + a); // 6
// ── Pattern 4: Sentinel-controlled input ──────────────────────────────
Scanner scanner = new Scanner(System.in);
int total = 0;
int inputCount = 0;
System.out.println("Enter numbers (-1 to stop):");
int input = scanner.nextInt();
while (input != -1) { // -1 is the sentinel
total += input;
inputCount++;
input = scanner.nextInt();
}
System.out.println("Sum: " + total);
System.out.println("Count: " + inputCount);
// ── Pattern 5: Power of two ───────────────────────────────────────────
// Find the smallest power of 2 >= n
int n2 = 100;
int power = 1;
while (power < n2) {
power *= 2;
}
System.out.println("Smallest power of 2 >= 100: " + power); // 128Reading from Files and Streams
While loops are the idiomatic way to consume data from readers, streams, and scanners because the end-of-data condition is naturally expressed as a boolean: "while there is more data, process it." The loop variable is the result of the read operation itself — null for BufferedReader.readLine(), -1 for InputStream.read(), and hasNextLine() as the condition for Scanner.
The pattern is always the same: initialise the read variable before the loop, check it in the condition, use it in the body, and update it at the end of the body. Updating inside the body rather than in a header makes the intent clear even when the "update" is a complex read expression.
Java
// ── Reading all lines from a file ────────────────────────────────────
try (BufferedReader reader = new BufferedReader(
new FileReader("data.txt"))) {
String line = reader.readLine(); // initialise BEFORE loop
while (line != null) { // null signals end-of-file
processLine(line);
line = reader.readLine(); // update at END of body
}
}
// ── More concise — assign in condition ───────────────────────────────
// Java allows assignment inside the condition expression
try (BufferedReader reader = new BufferedReader(
new FileReader("data.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line);
}
}
// ── Reading raw bytes ─────────────────────────────────────────────────
try (InputStream in = new FileInputStream("file.bin")) {
int byteValue;
while ((byteValue = in.read()) != -1) {
processByte((byte) byteValue);
}
}
// ── Scanner — consuming all tokens ───────────────────────────────────
Scanner scanner = new Scanner(new File("numbers.txt"));
List<Integer> numbers = new ArrayList<>();
while (scanner.hasNextInt()) {
numbers.add(scanner.nextInt());
}
scanner.close();
// ── Iterator pattern ─────────────────────────────────────────────────
// The enhanced for loop is backed by an Iterator
// Sometimes you need the Iterator directly (to call remove())
List<String> names = new ArrayList<>(
List.of("Alice", "Bob", "Carol", "Dave"));
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
if (name.startsWith("C")) {
it.remove(); // safe removal during iteration
}
}
System.out.println(names); // [Alice, Bob, Dave]Infinite Loops and Controlled Exit
An infinite while loop — while (true) — intentionally has no exit condition in the header. Instead it relies on break, return, or throw inside the body to terminate. This pattern is clear and honest: the loop runs forever by design, and the exit conditions are explicit inside the body. It is commonly used for server main loops, event dispatch loops, game loops, and retry loops where the continuation condition is complex or emerges mid-body.
Using while (true) with break is often cleaner than contorting a condition to fit the header, especially when the decision to exit occurs in the middle of the body after some computation has already happened.
Java
// ── Retry with exponential backoff ──────────────────────────────────
int maxAttempts = 5;
int attempt = 0;
boolean success = false;
while (true) {
attempt++;
try {
callExternalService();
success = true;
break; // exit on success
} catch (ServiceUnavailableException ex) {
if (attempt >= maxAttempts) {
throw new RuntimeException(
"Service unavailable after " + attempt +
" attempts", ex);
}
long delay = (long) Math.pow(2, attempt) * 100;
System.out.println("Retry " + attempt +
" in " + delay + "ms");
Thread.sleep(delay);
}
}
// ── Input validation loop ─────────────────────────────────────────────
Scanner scanner = new Scanner(System.in);
int validAge;
while (true) {
System.out.print("Enter your age (1-120): ");
if (!scanner.hasNextInt()) {
System.out.println("Please enter a number.");
scanner.next(); // consume invalid token
continue;
}
validAge = scanner.nextInt();
if (validAge >= 1 && validAge <= 120) {
break; // valid input — exit loop
}
System.out.println("Age must be between 1 and 120.");
}
System.out.println("Valid age: " + validAge);
// ── Game loop ─────────────────────────────────────────────────────────
GameState state = GameState.initial();
while (true) {
state.render();
Input input = state.readInput();
if (input == Input.QUIT) break;
state = state.update(input);
if (state.isGameOver()) {
state.showGameOverScreen();
break;
}
}
// ── Thread-safe server loop ───────────────────────────────────────────
volatile boolean running = true; // volatile ensures visibility
while (running) {
Request request = server.accept();
processAsync(request);
}
// Another thread sets running = false to shut downCommon Mistakes and How to Avoid Them
The while loop's simplicity conceals several traps. The most dangerous is an infinite loop caused by forgetting to update the loop variable. The subtlest is the off-by-one error — deciding whether the condition should be < versus <= often requires careful thought. Using the wrong equality operator (= instead of ==) can cause a compile error in Java (unlike C), which actually protects developers from this common bug.
Java
// ── Mistake 1: Forgetting to update the loop variable ────────────────
int i = 0;
while (i < 10) {
System.out.println(i);
// i++ missing → INFINITE LOOP
}
// Fix:
while (i < 10) {
System.out.println(i);
i++; // ← must update
}
// ── Mistake 2: Update in wrong place ─────────────────────────────────
int count2 = 1;
while (count2 <= 5) {
count2++; // update BEFORE use — skips first value
System.out.println(count2); // prints 2 3 4 5 6 (wrong)
}
// Fix: update AFTER use
int count3 = 1;
while (count3 <= 5) {
System.out.println(count3); // prints 1 2 3 4 5
count3++;
}
// ── Mistake 3: Condition uses wrong operator ──────────────────────────
// In Java, assignment in condition causes compile error (not boolean)
// while (i = 10) { ... } // ← compile error — int not boolean
// ── Mistake 4: Condition never becomes false ──────────────────────────
// Often from using wrong comparison operator
double x = 0.0;
while (x != 1.0) { // floating-point arithmetic may skip 1.0 exactly
x += 0.1; // INFINITE LOOP — x may go 0.9999, 1.0000001
}
// Fix: use epsilon comparison for floating point
while (x < 1.0 - 1e-9) {
x += 0.1;
}
// ── Mistake 5: Loop body is empty ────────────────────────────────────
// Semicolon after while creates empty body — easy to miss
while (count < 10); // ← semicolon ends the statement
{ // ← this block always runs once, not in loop
System.out.println(count);
}Related Topics in Control Statements
Control Statements
Control statements determine the flow of execution in a Java program. Without them, code executes line by line from top to bottom. Control statements allow the program to make decisions, repeat actions, and jump to different parts of the code based on conditions. Java provides three categories: selection statements (if, if-else, switch), iteration statements (for, while, do-while), and jump statements (break, continue, return).
if Statement
The if statement is the most fundamental control flow construct in Java. It evaluates a boolean expression and executes a block of code only if the expression is true. If the condition is false the block is skipped entirely and execution continues with the next statement after the if block.
if-else Statement
The if-else statement extends the basic if by providing an alternative block that executes when the condition is false. It guarantees that exactly one of two blocks always executes — either the if block (condition true) or the else block (condition false). The if-else-if chain extends this to choose among more than two alternatives.
Nested if
A nested if is an if statement placed inside the body of another if or else block. Nesting allows multi-level decision making — first check a broad condition, then refine with a more specific condition inside it. While nesting is sometimes necessary, deep nesting quickly reduces readability and should be refactored using guard clauses, logical operators, or extracted methods.