Java Loops
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:
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:
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:
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:
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:
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:
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:
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; }
}
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
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.
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
- Print the numbers 1 to 10 with a
forloop, then again with awhileloop. - Print the first 10 even numbers using a
forloop andcontinueto skip odd ones. - Iterate an array of Strings and print only those with length greater than 4 using
for-each. - Compute the factorial of 10 with a
forloop, then again with a Stream ofIntStream.rangeClosed.