Topic 2.8
break, continue and Labels
In one line
break leaves the innermost loop or switch at once; continue skips the rest of the current iteration and moves to the next. A label lets either one target an outer loop, which is the clean way to stop nested loops.
Think of it like this
Looking for your keys in a row of drawers. As soon as you find them, you stop searching (that's break). If a drawer is locked, you skip it and move to the next drawer (that's continue). If the keys are in a box inside a drawer, finding them should end the whole search, not just the box: that's a labelled break.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- break
- Leave the nearest enclosing loop or switch immediately.
- continue
- Skip the rest of this iteration and go on with the next one.
- Label
- A name with a colon, like
outer:, written before a loop sobreak/continuecan refer to it. - Innermost
- The closest enclosing one. In nested loops, the inner loop is innermost.
- Flag
- A
booleanvariable used to remember that something happened, likefound = true. - Early exit
- Leaving a loop or method before it would normally finish, because the answer is already known.
Step by step
01break: stop as soon as you know
Searching for the first negative number: once found, looking further is wasted work. break jumps straight to the statement after the loop.
Notice the found index declared before the loop, so its value survives (Topic 2.6). Starting it at -1, a sentinel meaning 'not found', is a common idiom.
int[] values = {4, 7, -2, 9, -5};
int found = -1;
for (int i = 0; i < values.length; i++) {
if (values[i] < 0) {
found = i;
break; // stop at the first negative
}
}
System.out.println("First negative at index " + found); // 202continue: skip this one
continue skips the rest of the body for the current element. In a for loop the update i++ still runs, so the loop moves on normally.
It's the loop version of a guard clause (Topic 2.1): deal with the uninteresting cases at the top, so the main work isn't nested inside an if.
for (int i = 1; i <= 10; i++) {
if (i % 3 != 0) {
continue; // not a multiple of 3: skip
}
System.out.print(i + " "); // 3 6 9
}03Where each one jumps
break jumps out, past the end of the loop. continue jumps to the next round: the update and condition in a for, the condition in a while.
Watch out in while loops: if the counter update is at the bottom of the body, continue skips it and the loop never ends. In a for loop the update lives in the header, so it's safe.
04break inside a switch inside a loop
Here break leaves the switch, not the loop. The loop keeps going after "stop" and prints quit.
With an arrow-form switch (Topic 2.4) there's no fall-through, so the break would not be needed for the switch at all. But a break inside an arrow switch statement still only leaves the switch.
String[] commands = {"go", "stop", "quit"};
for (String c : commands) {
switch (c) {
case "stop":
System.out.println("stopping?");
break; // leaves the switch only!
default:
System.out.println(c);
}
}05Labels: break out of nested loops
Put a label before the outer loop, and break outer; leaves both loops at once. Without the label, break only ends the inner loop and the outer loop carries on.
The label name is any identifier; outer, search and rows are common. Convention is lower case, on its own line or just before the loop.
int[][] grid = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int target = 5;
outer:
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c] == target) {
System.out.println("Found at row " + r + ", col " + c);
break outer; // leaves both loops
}
}
}06continue with a label
continue outer; abandons the inner loop and starts the next iteration of the outer one. Use it when one bad item in an inner loop means the whole outer item should be skipped.
Below, a row containing a negative number is rejected as soon as the negative is seen.
int[][] rows = {{1, 2}, {3, -1}, {5, 6}};
rows:
for (int[] row : rows) {
for (int v : row) {
if (v < 0) {
continue rows; // skip the rest of this row
}
}
System.out.println("row ok: " + Arrays.toString(row));
}07Alternatives: flag, method and return
A flag (boolean found) checked in the outer condition also works, but adds a variable and a check on every iteration.
Often the cleanest option is to move the search into its own method and return the answer: return leaves every loop at once. You'll do this a lot once you've learned methods in Phase 3.
Try it yourself
- 1
Remove the label
In 'Labelled break and continue', change
break search;tobreak;. Predict the 'Cells checked' count, then run. (It becomes 8: the inner loop stops at 5, but the outer loop carries on with row 2.) - 2
Create the while-loop trap
In 'continue in a while loop', move
i++to the last line of the body. Predict what happens, run it, and stop the program. The loop sticks ati = 0, which is even, socontinuejumps back beforei++ever runs.
Code & diagrams
Expected output
First negative at index 2
Multiples of 3: 3 6 9
Sum of non-negatives: 20Expected output
Found 5 at row 1, col 1
Cells checked: 5
row ok: [1, 2]
rejected: [3, -1]
row ok: [5, 6]Expected output
Plain break (leaves the switch only):
go
stop seen
quit
Labelled break (leaves the loop):
go
stop seenIf `i++` were at the bottom of the body, `continue` would skip it and the loop would never end.
Expected output
1 3 5 7 9Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
break outside a loop
Use break inside an if that isn't in any loop or switch.
public class Main {
public static void main(String[] args) {
int x = 1;
if (x > 0) {
break;
}
}
}Break #2
continue to a label that isn't a loop
Label a plain block and continue to it.
public class Main {
public static void main(String[] args) {
outer:
{
for (int i = 0; i < 3; i++) {
continue outer;
}
}
}
}Break #3
Misspell a label
Write break outer; with no outer: label in scope.
Myth vs fact
Myth
break always leaves the loop.
Fact
It leaves the innermost loop or switch. Inside a switch in a loop, it leaves only the switch.
Myth
Labels are Java's goto.
Fact
Labels can only be targeted by break and continue from inside the labelled statement, so jumps are always structured. goto is reserved but unused.
Myth
continue skips the update in a for loop.
Fact
In a for loop, continue runs the update and then the condition. It's in while loops that a hand-written update can be skipped.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
JLS 14.15–14.16 define
breakandcontinuein terms of 'abrupt completion' with a reason; anyfinallyblocks in between still run. Abreakthat jumps out of atrywith afinallyexecutes thefinallyfirst, which is whyjavacduplicatesfinallycode at every exit. - ▸
Labelled jumps compile to the same
gotoas unlabelled ones; labels don't exist in bytecode. Neither costs anything at run time. - ▸
A
breakinside a switch expression isn't allowed to leave the expression (attempt to break out of a switch expression), and neither iscontinueorreturn; the expression must yield a value or throw. - ▸
Static analysers flag loops with many exits (Sonar S135: 'Loops should not contain more than a single break or continue statement'). Extracting a method with
returnis usually the readable fix.
Remember this
- 1
breakends the innermost enclosingfor,while,do-whileorswitchimmediately. Execution continues with the first statement after it. Use it to stop a search as soon as you have the answer. - 2
continueends only the current iteration. In awhileordo-while, Java jumps to the condition check; in afor, it runs the update first (i++) and then checks. Use it to skip items that don't need processing, as a guard clause for loops. - 3
A label is a name followed by a colon placed before a statement, like
outer:.break outer;leaves the labelled statement entirely;continue outer;jumps to the next iteration of the labelled loop. Labels are the reason Java doesn't needgoto(it's a reserved word that does nothing). - 4
A
breakinside aswitchthat sits inside a loop leaves only the switch, not the loop. This surprises many people. Use a labelled break, a flag, or areturnto leave the loop. - 5
The compiler checks the targets:
breakoutside any loop or switch,continueoutside a loop, an unknown label, orcontinueon a label that isn't a loop are all compile errors. A label can also be put on a plain block and left withbreak, though that's rare. - 6
In bytecode,
breakandcontinueare plaingotojumps. They cost nothing. Their only cost is readability: several exits from one loop make it harder to reason about, so many teams prefer extracting the loop into a method and usingreturn.
Explain it without notes
What's the difference between break and continue?
Why does a break inside a switch inside a loop not stop the loop, and how do you stop the loop?
How does continue behave differently in a for loop and a while loop?
What alternatives to a labelled break exist for leaving nested loops?
Practice
Print the numbers from 1 to 20, skipping multiples of 4, and stop completely when you reach a number greater than 15.
Find the first pair of numbers in {3, 8, 11, 4, 7} that add up to 15, using nested loops and a labelled break, and print the pair.
Using continue, print only the words in {"apple", "", "kiwi", " ", "plum"} that are not blank.
Trade-offs
- ↔
breakfor early exit saves work and states intent, but several exits from one loop make its behaviour harder to follow. - ↔
Labelled breaks are precise and cheap, but unfamiliar to many developers; extracting a method with
returnis often more readable. - ↔
continueflattens nested ifs in a loop body, but inwhileloops it can skip the update and hang the program.
Done when you can
Done when you can use break to stop a search and continue to skip items.
Done when you can leave nested loops with a labelled break and skip an outer iteration with a labelled continue.
Done when you can explain why break inside a switch doesn't stop the enclosing loop.
Done when you can spot the continue-skips-the-update bug in a while loop.
Done when you know the compile errors for misplaced break, continue and labels.