Nested loops and labels
A runner's workout often consists of sets. The coach says: "Three sets of three laps." The runner runs three laps, rests, runs three laps again, and so on three times. That is a repeat inside a repeat.
In a program this is a nested loop: a loop that stands in the body of another loop. The outer loop counts the sets, the inner one the laps within a set. Here is a multiplication table from 1 to 3:
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
System.out.print(i * j + " ");
}
System.out.println();
}
}
}The program prints three lines:
1 2 3
2 4 6
3 6 9Let's walk through the program:
- The outer loop takes
iequal to1. - The inner loop runs
jfrom1to3and prints1 2 3. System.out.println()with no arguments only ends the line.- The outer loop moves on to
iequal to2, and the inner loop again runs through everyjfrom1to3.
For each iteration of the outer loop, the inner loop runs in full. That is why the body of the inner loop ran 3 * 3 times, that is, nine times. Each loop has its own variable: i is the table's row number, j its column number.
break in a nested loop
Suppose you need to find the first pair of numbers in the table whose product is 6, and stop there. The first attempt is a plain break:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i * j == 6) {
System.out.print(i + "*" + j + " "); // 2*3 3*2
break;
}
}
}The program found two pairs instead of one. break ends only the nearest loop whose body it stands in, the inner one. The outer loop did not notice, moved on to i equal to 3, and found the second pair 3*2.
The same goes for the runner. A "stop" in the middle of a set ends the set, but not the workout: after the rest, the next set begins. To end the whole workout, the coach has to name it: "the workout is over".
Labels
A loop label is a name with a colon in front of a loop, for example outer:. All it shares with the case labels of a switch is the colon. You make up the label's name yourself, like a variable name, and write it on the same line as the loop or on the line above. The label does nothing by itself: it only gives the loop a name that break and continue can refer to.
break with a label
break outer ends the loop labeled outer, even when it stands in the inner loop:
outer: for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i * j == 6) {
System.out.print(i + "*" + j + " "); // 2*3
break outer;
}
}
}Let's see what happens:
- While
iis1, no product equals6. - When
iis2andjis3, the condition is true, and the program prints2*3. break outerends both the inner and the outer loop.inever gets to3.
After break outer, execution goes on to the statement after the labeled loop. It is not a jump back to the label: the label only names the loop to end.
This is where the coach picture falls short. The coach can shout "stop" from anywhere. In Java, break outer works only inside the loop labeled outer, and outside it the compiler answers undefined label: outer.
Interviewers often ask how to leave two nested loops at once. The answer is break with a label.
continue with a label
continue outer skips the rest of the outer loop's iteration. The inner loop is cut off in the middle, and the outer one moves on to the next i. For the runner, this is the command "the set is over, start the next one". You use it when a single j already shows that the rest of the table row is not needed.
Common mistake
The break stands inside a switch, and the switch inside a loop:
for (int i = 1; i <= 5; i++) {
switch (i) {
case 3:
System.out.print("stop ");
break; // ✗
default:
System.out.print(i + " ");
}
}The goal was to end the loop at three, but the program prints 1 2 stop 4 5. A break inside a switch belongs to the switch itself: it leads out of the switch, and the loop goes on. Put a label on the loop, loop: for (…), and write break loop. Then the loop ends at three, and the program prints 1 2 stop.
Key points
- In a nested loop, the inner loop runs in full for each iteration of the outer one.
- Without a label,
breakandcontinueact only on the nearest loop, and abreakinside aswitchonly on theswitch. break outerends the loop labeledouter:, andcontinue outermoves on to its next iteration.- A label is not a place to jump back to: after
break outer, execution goes on to the statement after the labeled loop.