Java Loops

BEGINNER ~8 min read Tutorial

Loops let a program execute the same block of code multiple times. Java has four loop constructs: while, do-while, for, and the enhanced for-each. Each has a sweet spot — this tutorial explains when to use which, and how to choose between them and the functional style offered by Streams.

Loops are how you process arrays, collections, lines in a file, records from a database, and any other sequence. Get comfortable with all four forms; you will use them every day.

1. while Loop

The while loop tests its condition before each iteration. If the condition is initially false, the body never runs:

java
int i = class="tok-num">0;
while (i < class="tok-num">5) {
    System.out.println("i = " + i);
    i++;
}

class=class="tok-str">"tok-cmt">// read lines until end-of-file
String line;
while ((line = reader.readLine()) != null) {
    process(line);
}

Use while when you do not know in advance how many times you will iterate — reading input until end-of-file, polling a queue, or retrying a network call.

2. do-while Loop

The do-while loop tests its condition after each iteration, so the body always runs at least once:

java
int choice;
do {
    choice = showMenuAndGetChoice();
    handleChoice(choice);
} while (choice != QUIT);

class=class="tok-str">"tok-cmt">// body runs at least once even if condition is initially false
int n = class="tok-num">10;
do {
    System.out.println(n);
} while (n < class="tok-num">5);   class=class="tok-str">"tok-cmt">// prints class="tok-num">10 once

This is the form to reach for when you want to do something at least once and then decide whether to repeat. Menu loops and input validation are classic use cases.

3. for Loop

The classic for loop has three parts separated by semicolons: initialisation, condition, and update. All three are optional:

java
class=class="tok-str">"tok-cmt">// classic counting loop
for (int i = class="tok-num">0; i < class="tok-num">5; i++) {
    System.out.println(i);
}

class=class="tok-str">"tok-cmt">// multiple counters and complex updates
for (int i = class="tok-num">0, j = class="tok-num">10; i < j; i++, j--) {
    System.out.println(i + " " + j);
}

class=class="tok-str">"tok-cmt">// infinite loop with explicit break
for (;;) {
    String input = readInput();
    if ("quit".equals(input)) break;
    handle(input);
}

Use for when you know in advance how many times to iterate, or when you need the index variable. The three slots can hold any expression, not just simple counters.

4. The Enhanced for-each Loop

Java 5 added the enhanced for loop, which iterates over arrays and any Iterable without exposing the index:

java
String[] names = {"Alice", "Bob", "Carol"};
for (String name : names) {
    System.out.println(name);
}

class=class="tok-str">"tok-cmt">// works on any Iterable (List, Set, Queue, etc.)
List<Integer> nums = List.of(class="tok-num">1, class="tok-num">2, class="tok-num">3, class="tok-num">4, class="tok-num">5);
int sum = class="tok-num">0;
for (int n : nums) {
    sum += n;
}

Use for-each when you do not need the index. It is more concise, less error-prone, and works uniformly across arrays, List, Set, and any custom Iterable.

5. break and continue

break exits the current loop immediately. continue skips the rest of the current iteration and proceeds to the next:

java
class=class="tok-str">"tok-cmt">// break - find the first even
int[] nums = {class="tok-num">1, class="tok-num">3, class="tok-num">5, class="tok-num">6, class="tok-num">7, class="tok-num">8};
for (int n : nums) {
    if (n % class="tok-num">2 == class="tok-num">0) {
        System.out.println("First even: " + n);
        break;
    }
}

class=class="tok-str">"tok-cmt">// continue - skip negatives
int sum = class="tok-num">0;
for (int n : nums) {
    if (n < class="tok-num">0) continue;
    sum += n;
}

class=class="tok-str">"tok-cmt">// labelled break - exit outer loop
outer:
for (int i = class="tok-num">0; i < class="tok-num">10; i++) {
    for (int j = class="tok-num">0; j < class="tok-num">10; j++) {
        if (foundMatch(i, j)) break outer;
    }
}

Both can also use labelled form to act on an outer loop, though that is rarely needed in modern Java because the Streams API often replaces it more cleanly.

6. Nested Loops

Loops can nest. The classic example is iterating a 2-D structure:

java
int[][] grid = {
    {class="tok-num">1, class="tok-num">2, class="tok-num">3},
    {class="tok-num">4, class="tok-num">5, class="tok-num">6},
    {class="tok-num">7, class="tok-num">8, class="tok-num">9}
};

for (int i = class="tok-num">0; i < grid.length; i++) {
    for (int j = class="tok-num">0; j < grid[i].length; j++) {
        System.out.printf("grid[%d][%d] = %d%n", i, j, grid[i][j]);
    }
}

class=class="tok-str">"tok-cmt">// for-each version
for (int[] row : grid) {
    for (int cell : row) {
        System.out.print(cell + " ");
    }
    System.out.println();
}

Avoid deep nesting — three levels is usually the limit before code becomes hard to follow. Extract the inner loops into helper methods when needed.

7. Streams vs Loops

Since Java 8 you can often replace a loop with a Stream. Both work; the choice is about clarity:

java
class=class="tok-str">"tok-cmt">// imperative loop with side effects
long count = class="tok-num">0;
for (String s : list) {
    if (s.startsWith("A")) count++;
}

class=class="tok-str">"tok-cmt">// declarative stream pipeline
long count2 = list.stream()
    .filter(s -> s.startsWith("A"))
    .count();

class=class="tok-str">"tok-cmt">// with early exit (no clean stream equivalent)
int firstNegative = -class="tok-num">1;
for (int n : nums) {
    if (n < class="tok-num">0) { firstNegative = n; break; }
}
Rule of thumb

Use a Stream when the operation is a declarative pipeline (filter/map/reduce). Use a loop when you need side effects, early exit based on complex conditions, or mutable accumulation that does not fit a collector.

8. Common Pitfalls

Infinite loop with no update

while (i < 10) { System.out.println(i); } never terminates because i never changes. Always make sure the loop variable is updated somewhere in the body.

Off-by-one errors

Forgetting the -1 when iterating an array: for (int i = 0; i <= arr.length; i++) throws ArrayIndexOutOfBoundsException on the last iteration. Use <, not <=, with array lengths.

Exercises

  1. Print the numbers 1 to 10 with a for loop, then again with a while loop.
  2. Print the first 10 even numbers using a for loop and continue to skip odd ones.
  3. Iterate an array of Strings and print only those with length greater than 4 using for-each.
  4. Compute the factorial of 10 with a for loop, then again with a Stream of IntStream.rangeClosed.