Command Palette

Search for a command to run...

PHASE 2Beginner ~28 min· topic 8 of 10

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 so break/continue can refer to it.
Innermost
The closest enclosing one. In nested loops, the inner loop is innermost.
Flag
A boolean variable used to remember that something happened, like found = 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.

Main.javawhole filejava
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);   // 2

02continue: 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.

Main.javawhole filejava
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.

Where each one jumpsdiagram
Rendering diagram…

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.

Main.javawhole filejava
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);
    }
}
terminal
$ java Main.java
── expected output ──
go
stopping?
quit

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.

Main.javawhole filejava
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.

Main.javawhole filejava
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. 1

    Remove the label

    In 'Labelled break and continue', change break search; to break;. 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. 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 at i = 0, which is even, so continue jumps back before i++ ever runs.

Code & diagrams

break and continue New tab
Sign in to run this example in your browser.

Expected output

First negative at index 2
Multiples of 3: 3 6 9
Sum of non-negatives: 20
Labelled break and continue New tab
Sign in to run this example in your browser.

Expected output

Found 5 at row 1, col 1
Cells checked: 5
row ok: [1, 2]
rejected: [3, -1]
row ok: [5, 6]
break in a switch inside a loop New tab
Sign in to run this example in your browser.

Expected output

Plain break (leaves the switch only):
  go
  stop seen
  quit
Labelled break (leaves the loop):
  go
  stop seen
continue in a while loop: keep the update first New tab

If `i++` were at the bottom of the body, `continue` would skip it and the loop would never end.

Sign in to run this example in your browser.

Expected output

1 3 5 7 9

Break 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.

Main.javawhole filejava
public class Main {
    public static void main(String[] args) {
        int x = 1;
        if (x > 0) {
            break;
        }
    }
}
terminal
$ javac Main.java
── what you'll see ──
Main.java:5: error: break outside switch or loop
break;
^
1 error

Break #2

continue to a label that isn't a loop

Label a plain block and continue to it.

Main.javawhole filejava
public class Main {
    public static void main(String[] args) {
        outer:
        {
            for (int i = 0; i < 3; i++) {
                continue outer;
            }
        }
    }
}
terminal
$ javac Main.java
── what you'll see ──
Main.java:6: error: not a loop label: outer
continue outer;
^
1 error

Break #3

Misspell a label

Write break outer; with no outer: label in scope.

terminal
$ javac Main.java
── what you'll see ──
Main.java:4: error: undefined label: outer
break outer;
^
1 error

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 break and continue in terms of 'abrupt completion' with a reason; any finally blocks in between still run. A break that jumps out of a try with a finally executes the finally first, which is why javac duplicates finally code at every exit.

  • ▸

    Labelled jumps compile to the same goto as unlabelled ones; labels don't exist in bytecode. Neither costs anything at run time.

  • ▸

    A break inside a switch expression isn't allowed to leave the expression (attempt to break out of a switch expression), and neither is continue or return; 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 return is usually the readable fix.

Remember this

  1. 1

    break ends the innermost enclosing for, while, do-while or switch immediately. Execution continues with the first statement after it. Use it to stop a search as soon as you have the answer.

  2. 2

    continue ends only the current iteration. In a while or do-while, Java jumps to the condition check; in a for, 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. 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 need goto (it's a reserved word that does nothing).

  4. 4

    A break inside a switch that sits inside a loop leaves only the switch, not the loop. This surprises many people. Use a labelled break, a flag, or a return to leave the loop.

  5. 5

    The compiler checks the targets: break outside any loop or switch, continue outside a loop, an unknown label, or continue on a label that isn't a loop are all compile errors. A label can also be put on a plain block and left with break, though that's rare.

  6. 6

    In bytecode, break and continue are plain goto jumps. 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 using return.

Explain it without notes

01

What's the difference between break and continue?

02

Why does a break inside a switch inside a loop not stop the loop, and how do you stop the loop?

03

How does continue behave differently in a for loop and a while loop?

04

What alternatives to a labelled break exist for leaving nested loops?

Practice

01

Print the numbers from 1 to 20, skipping multiples of 4, and stop completely when you reach a number greater than 15.

02

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.

03

Using continue, print only the words in {"apple", "", "kiwi", " ", "plum"} that are not blank.

Trade-offs

  • ↔

    break for 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 return is often more readable.

  • ↔

    continue flattens nested ifs in a loop body, but in while loops 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.