Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Java  Module 3 – Control flow, methods and recursion

break, continue and labelled loops

Leave Java loops early with break, skip passes with continue, exit nested loops with a labelled break, and know when a method that returns is clearer.

  • Beginner
  • 20 minutes
  • Examples run with Java temurin-25.0.4+101.0.LTS and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 20 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Use break to stop a loop at the first match instead of carrying a flag
  • Predict where continue goes next in a for, a while and a do-while loop
  • Use a labelled break or continue to leave or skip an outer loop
  • Replace a labelled search with a method that returns its answer
  • Fix a break inside a switch that was meant to end the loop around it

Before you start

What you’ll learn · Before you start

What you will learn

  • Use break to stop a loop at the first match instead of carrying a flag
  • Predict where continue goes next in a for, a while and a do-while loop
  • Use a labelled break or continue to leave or skip an outer loop
  • Replace a labelled search with a method that returns its answer
  • Fix a break inside a switch that was meant to end the loop around it

Before you start

On this page

A loop that searched six sensor readings for the first one above 45 found it at position 3, kept going, and reported position 4. break ends a loop the moment the answer is known, and the program carries on with the statement after the loop; continue ends only the current pass and goes on with the next one. Both act on the innermost loop around them, and a break inside a switch ends only the switch. To leave a loop nested inside another, put a label: A name and a colon written before a statement, as in search: for (…). Inside that statement, break search; ends it, and continue search; goes on with its next pass when the statement is a loop. Java has no goto, so a label is used only this way., a name and a colon, before the outer loop: break search; leaves the loop labelled search, and continue search; goes on with its next pass.

You will step through each one and meet the two places where they surprise people: a continue that skips the update of a while loop, and a break in a switch that leaves the loop running. When two loops must stop together, a method that returns is often clearer still.

break stops a loop at the first match

Searching is the classic use. Here three loops look for the first reading above a limit of 45, and each counts how many readings it looked at:

Three ways to stop, or not Java · FirstAbove.java
// Find the first reading above the limit, three ways, and count how many readings each loop looks at.
int[] readings = {38, 41, 39, 47, 52, 40};
int limit = 45;

void main() {
    // 1. No way to stop: the loop goes on after the answer and keeps overwriting it.
    int position = -1;
    int looked = 0;
    for (int i = 0; i < readings.length; i++) {
        looked++;
        if (readings[i] > limit) {
            position = i;
        }
    }
    IO.println("never stops:  position " + position + ", looked at " + looked);

    // 2. A flag variable that the loop condition checks.
    position = -1;
    looked = 0;
    boolean found = false;
    for (int i = 0; i < readings.length && !found; i++) {
        looked++;
        if (readings[i] > limit) {
            position = i;
            found = true;
        }
    }
    IO.println("with a flag:  position " + position + ", looked at " + looked);

    // 3. break leaves the loop the moment the answer is known.
    position = -1;
    looked = 0;
    for (int i = 0; i < readings.length; i++) {
        looked++;
        if (readings[i] > limit) {
            position = i;
            break;
        }
    }
    IO.println("with break:   position " + position + ", looked at " + looked);
}

Output

never stops:  position 4, looked at 6
with a flag:  position 3, looked at 4
with break:   position 3, looked at 4

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java FirstAbove.java

The first loop never stops, so it keeps overwriting position and reports the last reading above 45, at position 4, not the first one, at 3. That is a real bug, and the cure is any way of stopping at the first match. The second loop uses a flag: A boolean variable that records that something has happened, such as found = true, so that a later test, often the loop condition, can act on it. A break or a return usually says the same thing more directly., a boolean that records “found it”, and tests it in the loop condition. It works, but the reader has to follow found through three lines to see why the loop ends. The third loop says it directly: break as soon as the answer is known. Step through it pass by pass, then see what the other two loops do:

Interactive · stage by stage The first reading above 45, found with break Step through the loop with break one pass at a time, then see what the loops without it do.
The first reading above 45, found with break, step 6 of 6. Showing i < readings.length ? (&& !found: false), readings[i] > limit ? (47 > 45: true), position = i; break; (found is true), after the loop (position 3, looked at 4). In focus: i < readings.length ?.no: i++false: leavei < readings.length ?&& !found: falsereadings[i] > limit ?47 > 45: trueposition = i; break;found is trueafter the loopposition 3, looked at 4

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Pass 1. i is 0, and 0 < 6 is true. readings[0] is 38, which is not above 45, so the pass ends, i++ makes i 1, and the loop goes back to its test.
  2. Passes 2 and 3. 41 and 39 are not above 45 either. After three passes, and three readings looked at, i is 3.
  3. Pass 4 finds 47. readings[3] is 47, and 47 > 45 is true, so position becomes 3. It is the fourth reading the loop has looked at.
  4. break. break ends the loop at once: neither i++ nor the test runs again. The line after the loop prints position 3, looked at 4.
  5. Without break. The first loop has no break. After position = 3 it goes on, finds 52 > 45 at position 4 and overwrites the answer, reads 40, and ends when 6 < 6 is false: position 4, after 6 readings.
  6. With a flag. The second loop sets found = true at position 3 instead. Its i++ still runs, then its test i < readings.length && !found is false, so it stops after the same 4 readings, one test later.

Both correct loops looked at 4 readings instead of 6, and on a long list the early exit is also the fast one: the work stops where the answer is.

Key idea

break ends the innermost loop at once, so a search that breaks at its first match keeps that match and reads nothing after it.

Checkpoint

Check: break stops at the first match

  1. Question 1 of 2 The readings of FirstAbove.java become {50, 41, 39, 47, 52, 40}. How many readings does the loop with break look at now?

    Type a number.

    A hint

    Where is the first reading above 45 now?

    Show the answer: Question 1 of 2

    Answer: 1 readings

    50 is above 45, so the first pass sets position to 0 and break ends the loop at once: one reading looked at. The loop without break would still look at all 6 and report position 4.

  2. Question 2 of 2 The flag loop is for (int i = 0; i < readings.length && !found; i++). Its body has just set found = true at i = 3. How does the loop end?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: i++ makes i 4, then the test is false and the loop ends

    A flag stops the loop at its next test, after the rest of the pass and the update have run. The loop looks at the same 4 readings as the version with break; the reader just has to follow found to see why it stops.

continue skips a pass, and in a while loop it can skip the update

continue jumps to the end of the current pass. In a for loop, the update still runs before the next test, which the language specification spells out for the basic for statement. In a while loop there is no separate update, so a continue that sits above the i++ skips it. This program counts the words of a line that has two spaces in a row, once with each loop:

The for loop counts the words; the while loop gets stuck Java · SkipSpaces.java
// Count the words in a line, jumping over the spaces between them with continue.
void main() {
    String line = "to be  or not";

    int words = 0;
    for (int i = 0; i < line.length(); i++) {
        if (line.charAt(i) == ' ') {
            continue; // the update i++ still runs before the next test
        }
        if (i == 0 || line.charAt(i - 1) == ' ') {
            words++;
        }
    }
    IO.println("for loop: " + words + " words");

    // The same loop as a while: continue jumps straight back to the test, past the i++ at the bottom.
    int passes = 0;
    int i = 0;
    words = 0;
    while (i < line.length()) {
        passes++;
        if (passes > 50) {
            IO.println("while loop: stopped by the safety limit, stuck at i = " + i);
            return;
        }
        if (line.charAt(i) == ' ') {
            continue;
        }
        if (i == 0 || line.charAt(i - 1) == ' ') {
            words++;
        }
        i++;
    }
    IO.println("while loop: " + words + " words");
}

Output

for loop: 4 words
while loop: stopped by the safety limit, stuck at i = 2

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java SkipSpaces.java

Step through both loops at the first space of the line, position 2:

Interactive · step by step Where continue goes in a for loop and in a while loop Step through both loops of SkipSpaces.java at the first space of the line, the for loop on the left and the while loop on the right.
Where continue goes in a for loop and in a while loop, step 6 of 6. Showing for: i < 13 ? (13 < 13: false, 4 words), a space? continue; (i = 2 is a space), i++ (i becomes 3), while: i < 13 ? (stopped after 50 passes), a space? continue; (i = 2 is a space), i++ (skipped). In focus: while: i < 13 ?.continuecontinueother charactersfor: i < 13 ?13 < 13: false, 4 wordsa space? continue;i = 2 is a spacei++i becomes 3while: i < 13 ?stopped after 50 passesa space? continue;i = 2 is a spacei++skipped

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Up to the space. The line "to be or not" has 13 characters. Both loops read t and o, count the first word, and reach a space at i = 2.
  2. for: continue. continue ends the pass. A for loop still runs its update before the next test, so i becomes 3 and the loop moves on to the b of be.
  3. for: 4 words. Every space is passed the same way, the update moving i on each time, and the for loop counts 4 words: to, be, or and not.
  4. while: continue. In the while loop, continue ends the pass as well, but this loop has no update of its own. It goes straight back to its test, past the i++ at the bottom of the body.
  5. while: stuck. 2 < 13 is still true, the character at 2 is still a space, and continue sends the loop back again: pass after pass, with i at 2.
  6. The safety limit. When its passes go over 50, the program's own limit stops the loop and prints stuck at i = 2. Without that limit the loop would never end. Move i++ above the continue, or write the loop as a for loop.

The for loop counts four words: at each space, continue skips the word test, and i++ still moves on. The while loop reaches the first space at position 2, continue sends it back to the test with i still 2, and it would test the same space for ever, an infinite loop: A loop whose condition never becomes false, so it runs until the program is stopped: nothing in its body moves it toward the exit, or a counter wraps round before it reaches its limit. More in “Loops: while, do-while, for and for-each”; only its safety limit of 50 passes stops it. A do-while loop behaves like the while loop here: after a continue it goes straight to its condition.

An update below a continue

while (i < n) { if (skip(i)) continue; … i++; } never gets past the first item it skips, because the continue jumps over i++. Write it as for (int i = 0; i < n; i++) { if (skip(i)) continue; … }, where the update runs after every pass, or move i++ above the continue.

Checkpoint

Check: continue skips the rest of a pass

  1. Question 1 of 2 What does this print?

    Read the code, then choose one answer.

    int n = 0;
    for (int i = 0; i < 5; i++) {
        if (i == 2) {
            continue;
        }
        n += i;
    }
    IO.println(n);
    Show the answer: Question 1 of 2

    Answer: 8

    continue ends the pass for i = 2 before n += i runs. The for loop then runs its update, i becomes 3, and the remaining passes add 3 and 4.

  2. Question 2 of 2 What does this do?

    Read the code, then choose one answer.

    int i = 0;
    while (i < 5) {
        if (i == 2) {
            continue;
        }
        IO.print(i + " ");
        i++;
    }
    Show the answer: Question 2 of 2

    Answer: It prints 0 1, and then the loop never ends

    This is the while loop of SkipSpaces.java in miniature: a continue above the update leaves the loop testing the same value for ever. Write it as a for loop, or move i++ above the continue.

A labelled break leaves the outer loop, a plain one only the inner

A seat map is a grid: rows of seats, X for booked and . for empty. The programs keep it in a String array, one string per row, and read seat c of row r with rows[r].charAt(c); arrays get a module of their own next. Finding the first empty seat needs a loop over the rows with a loop over the seats inside it, and a plain break leaves only the inner one. This program searches the same map both ways:

A plain break against a labelled one Java · FirstEmptySeat.java
// A seat map: one string per row, 'X' for a booked seat and '.' for an empty one.
String[] rows = {
    "XXXXXX",
    "XXX.X.",
    "X.XXXX",
};

void main() {
    // Without a label, break leaves only the inner loop, so every row reports its own first empty seat.
    for (int r = 0; r < rows.length; r++) {
        for (int c = 0; c < rows[r].length(); c++) {
            if (rows[r].charAt(c) == '.') {
                IO.println("plain break: row " + r + ", seat " + c);
                break;
            }
        }
    }

    // With a label, break search leaves the outer loop at the first empty seat of the whole map.
    int foundRow = -1;
    int foundSeat = -1;
    search:
    for (int r = 0; r < rows.length; r++) {
        for (int c = 0; c < rows[r].length(); c++) {
            if (rows[r].charAt(c) == '.') {
                foundRow = r;
                foundSeat = c;
                break search;
            }
        }
    }
    IO.println("labelled break: row " + foundRow + ", seat " + foundSeat);
}

Output

plain break: row 1, seat 3
plain break: row 2, seat 1
labelled break: row 1, seat 3

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java FirstEmptySeat.java

The plain break ends the search of one row, and the outer loop goes on with the next, so the program reports an empty seat in every row that has one. The label search: names the outer loop, and break search; ends that whole statement, so the program stops at the first empty seat of the map. The diagram shows where each one goes:

Nested seat search: a plain break leaves only the inner loop and goes on to the next row; break search leaves both loops.search: for each row rafter the searchfor each seat con to row r + 1seat empty?breakbreak searchevery row read

A plain break leaves one loop; a labelled break leaves the labelled statement

Text description of the diagram

The figure shows two nested loops. The outer loop carries the label search and goes through the rows. Inside it, the inner loop goes through the seats of one row and tests whether seat c is empty.

  • A plain break in the inner loop leaves only the inner loop. Control reaches the end of the outer loop's pass for this row, and the outer loop goes on to row r + 1.
  • break search leaves the statement labelled search, which is the outer loop, so control goes straight to the code after the search.
  • When the outer loop has read every row, it ends by itself, and control reaches the code after the search that way too.

So a plain break finds the first empty seat of every row, while break search stops at the first empty seat of the whole map.

Step through both searches on the three rows of FirstEmptySeat.java, XXXXXX, XXX.X. and X.XXXX:

Interactive · step by step A plain break and a labelled break on one seat map Step through both searches of FirstEmptySeat.java on its three rows, XXXXXX, XXX.X. and X.XXXX.
A plain break and a labelled break on one seat map, step 6 of 6. Showing search: for each row r (r = 1: XXX.X.), for each seat c (c = 3), seat c empty? (yes: seat 3), on to row r + 1, after the search (row 1, seat 3). In focus: after the search.breakbreak searchsearch: for each row rr = 1: XXX.X.for each seat cc = 3seat c empty?yes: seat 3on to row r + 1the outer loop goes onafter the searchrow 1, seat 3

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Row 0. The outer loop starts with row 0, XXXXXX. The inner loop checks its six seats, finds no empty one and ends by itself, so the outer loop goes on to row 1.
  2. Row 1, seat 3. Row 1 is XXX.X. Seats 0 to 2 are booked and seat 3 is empty: the first empty seat of the map, found after 10 seat checks.
  3. A plain break. The first search prints plain break: row 1, seat 3 and runs break. A plain break ends only the innermost loop, the seat loop, so the outer loop goes on to row 2.
  4. Row 2 as well. Row 2, X.XXXX, has an empty seat 1, so the plain search prints a second line, plain break: row 2, seat 1, after 12 seat checks in all.
  5. break search. The second search makes the same checks up to row 1, seat 3, then runs break search. The label names the outer loop, so the whole search ends there, after 10 checks.
  6. One answer. The line after the search prints labelled break: row 1, seat 3, one seat for the whole map, which is what the search was for.

The language specification puts it precisely: a break with a label completes the statement that carries that label. Here that happens after 10 seat checks, where the plain search made 12 and printed two seats. Java has no goto; a label can only be the target of break or continue, and only from inside the labelled statement.

Key idea

A plain break ends the innermost loop or switch around it; break search; ends the statement labelled search, however deep inside it the break sits.

Checkpoint

Check: A labelled break leaves an outer loop

  1. Question 1 of 2 The seat map of FirstEmptySeat.java becomes {"XX.", "X..", "..."}. How many lines does the search with the plain break print?

    Type a number.

    Show the answer: Question 1 of 2

    Answer: 3 lines

    Every row has an empty seat, and a plain break ends only the seat loop, so every row prints its own first empty seat: row 0 seat 2, row 1 seat 1 and row 2 seat 0. The labelled search would print one line, row 0, seat 2.

  2. Question 2 of 2 In FirstEmptySeat.java, break search; runs at row 1, seat 3. What runs next?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The line after the outer loop, which prints labelled break with row 1, seat 3

    A labelled break ends the statement with that label, however deeply the break is nested inside it. Here that is the outer loop, so both loops end and the print after them runs.

continue with a label moves on to the outer loop’s next pass

continue takes a label too. In EmptyRows.java, continue rows; abandons the current row at its first booked seat, runs the outer loop’s update and starts on the next row, so only completely empty rows reach the line that prints:

Only the rows with no booked seat are printed Java · EmptyRows.java
String[] rows = {
    "XXXXXX",
    "......",
    "X.XXXX",
    "......",
};

void main() {
    // continue rows abandons the current row at its first booked seat and moves on to the next row.
    rows:
    for (int r = 0; r < rows.length; r++) {
        for (int c = 0; c < rows[r].length(); c++) {
            if (rows[r].charAt(c) == 'X') {
                continue rows;
            }
        }
        IO.println("row " + r + " is empty");
    }
}

Output

row 1 is empty
row 3 is empty

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java EmptyRows.java

Step through its four rows and watch where continue rows sends the run:

Interactive · stage by stage continue rows on four rows of seats Step through EmptyRows.java row by row and watch where continue rows sends the run.
continue rows on four rows of seats, step 5 of 5. Showing rows: for each row r (r = 3: ......), for each seat c (6 seats, no X), print: row r is empty (row 3 is empty). In focus: rows: for each row r, print: row r is empty.continue rowsr++rows: for each row rr = 3: ......for each seat c6 seats, no Xprint: row r is emptyrow 3 is empty

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. Row 0. Row 0 is XXXXXX. Seat 0 is booked, so continue rows abandons the row after one check: the outer loop's r++ runs and row 1 starts. Nothing is printed.
  2. Row 1. Row 1 is six empty seats. The seat loop checks all six and ends by itself, so the run reaches the print: row 1 is empty.
  3. Row 2. Row 2 is X.XXXX. Seat 0 is booked, and continue rows moves on after one check, so the empty seat 1 never matters.
  4. Row 3. Row 3 is empty again, so the run prints row 3 is empty. Then r++ makes r 4, and the test r < 4 ends the loop.
  5. 14 checks. The run made 1 + 6 + 1 + 6 = 14 seat checks and printed two lines. A plain continue would only move on to the next seat, so every row would reach the print.

Rows 0 and 2 each end at seat 0, their first X, after one check, while rows 1 and 3 run all six checks and print. That is what the label is for. A plain continue would only move on to the next seat: every row’s seat loop would run to its end, and all four rows would be reported as empty. Without a label, the same job takes a flag set inside the seat loop and tested after it.

Checkpoint

Check: continue with a label

  1. Question 1 of 2 EmptyRows.java runs on the rows {"......", "..X...", "X....."}. How many seat checks does it make in all?

    Type a number.

    A hint

    Count the checks of each row up to and including its first X.

    Show the answer: Question 1 of 2

    Answer: 10 checks

    Row 0 has no X, so all 6 seats are checked and it prints row 0 is empty. Row 1 stops at its X in seat 2, after 3 checks, and row 2 at seat 0, after 1 check: 6 + 3 + 1 = 10.

  2. Question 2 of 2 If continue rows; in EmptyRows.java were a plain continue;, what would the program print for its four rows?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: All four lines, row 0 is empty to row 3 is empty

    Without the label, continue acts on the innermost loop, the seat loop. The X seats are skipped one at a time, but each row's loop still ends normally and the print runs for every row.

A method that returns ends every loop at once

Labels make the reader look for the line with the name. When the search is a job of its own, give it a method: return leaves every loop of the method at once, and the caller gets the answer as a value.

The same answer, with no label and no flag Java · SeatMethod.java
String[] rows = {
    "XXXXXX",
    "XXX.X.",
    "X.XXXX",
};

// The search as a method: return leaves both loops at once and hands the answer to the caller.
String firstEmptySeat() {
    for (int r = 0; r < rows.length; r++) {
        for (int c = 0; c < rows[r].length(); c++) {
            if (rows[r].charAt(c) == '.') {
                return "row " + r + ", seat " + c;
            }
        }
    }
    return "no empty seat";
}

void main() {
    IO.println("method with return: " + firstEmptySeat());
}

Output

method with return: row 1, seat 3

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java SeatMethod.java

Step through the call, from main into the method and back:

Interactive · message by message return hands the seat back and ends both loops Step through the call of firstEmptySeat() in SeatMethod.java, on the same three rows of seats.
return hands the seat back and ends both loops, step 6 of 6. Messages so far: main to firstEmptySeat(): firstEmptySeat(); firstEmptySeat() to main: row 1, seat 3.mainprints the answerfirstEmptySeat()two nested loopsfirstEmptySeat()row 1, seat 3returns no empty seat

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The call. main calls firstEmptySeat(), and the method's two loops start on row 0.
  2. Row 0. Row 0 is XXXXXX. The seat loop checks six booked seats and ends by itself, and the row loop goes on to row 1.
  3. Seat 3 of row 1. In row 1, seat 3 is the first dot, so the method runs its return with the text row 1, seat 3. return ends the method, and both of its loops with it.
  4. The value goes back. The value travels back to the call in main, so the call itself is worth row 1, seat 3. No label, no flag and no variables for the row and the seat were needed.
  5. main prints it. main prints method with return: row 1, seat 3, the same answer as the labelled break gave.
  6. When no seat is empty. With every seat booked, both loops would run to their end, and the return after them would hand back the text no empty seat instead.

firstEmptySeat() needs no label, no flag and no variables for the row and seat found; the “not found” case is the return after the loops. The four ways of this lesson to end a search compare like this:

Way to stop What it ends What the reader has to follow
No stop nothing: the loop runs to its end position, overwritten by every match
A flag in the condition the loop, at its next test found, set in the body and read in the header
break search; the statement labelled search the line that carries the label
return from a method every loop of the method the method’s name and the value it returns

Name the search

If you could give the search a name, such as “first empty seat”, write it as a method and return the answer. Keep a labelled loop for a short search in the middle of a method.

Checkpoint

Check: A method that returns ends every loop

  1. Question 1 of 2 Inside the two loops of firstEmptySeat(), what does its return with the row and seat do?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It ends both loops and the method, and hands the text back to the caller

    A return inside nested loops ends the method at once, whatever loops it sits in, and gives its value to the call. That is why the method needs no label, no flag and no variables for the seat it found.

  2. Question 2 of 2 Every seat of the map is booked. What does firstEmptySeat() return?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The text no empty seat, from the return after the loops

    The not-found case is simply the code after the loops: when no return inside them has run, the method falls out of both loops and returns no empty seat.

Inside a switch, break leaves the switch and not the loop

break leaves the innermost switch statement or loop around it, whichever is closer. In a command loop that means a break in the "quit" case ends the switch, and the loop carries on:

A quit command that does not quit, and the fix

The bug · CommandLoop.java

// Commands come from a list here; a real program would read them as they are typed.
String[] commands = {"add", "add", "quit", "add"};

void main() {
    int total = 0;
    int next = 0;
    while (next < commands.length) {
        String command = commands[next];
        next++;
        switch (command) {
            case "add":
                total++;
                IO.println("add -> total " + total);
                break;
            case "quit":
                IO.println("quit -> leaving the switch");
                break; // ends the switch, not the while loop
            default:
                IO.println("unknown command " + command);
        }
    }
    IO.println("after the loop: total " + total);
}

Output

add -> total 1
add -> total 2
quit -> leaving the switch
add -> total 3
after the loop: total 3

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java CommandLoop.java

With a labelled break · CommandLoopFixed.java

String[] commands = {"add", "add", "quit", "add"};

void main() {
    int total = 0;
    int next = 0;
    reading:
    while (next < commands.length) {
        String command = commands[next];
        next++;
        switch (command) {
            case "add" -> {
                total++;
                IO.println("add -> total " + total);
            }
            case "quit" -> {
                IO.println("quit -> leaving the loop");
                break reading;
            }
            default -> IO.println("unknown command " + command);
        }
    }
    IO.println("after the loop: total " + total);
}

Output

add -> total 1
add -> total 2
quit -> leaving the loop
after the loop: total 2

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java CommandLoopFixed.java

Step through the four commands, add, add, quit and add, in both versions:

Interactive · step by step What break does to a quit command, in both versions Step through the commands add, add, quit and add, with CommandLoop.java on the left and CommandLoopFixed.java on the right.
What break does to a quit command, in both versions, step 6 of 6. Showing quit: break; (total is 2), the loop goes on (add: total is 3), after the loop (total 3), quit: break reading; (total is 2), after the loop (total 2). In focus: after the loop.ends the switchtest is falseends the loopquit: break;total is 2the loop goes onadd: total is 3after the looptotal 3quit: break reading;total is 2after the looptotal 2

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Two adds. Both versions read add twice, and each add case adds 1, so both totals are 2 when the quit command comes.
  2. A plain break. CommandLoop.java prints quit -> leaving the switch and runs break. The closest statement a plain break can end is the switch, so the switch ends and the while loop goes on.
  3. The fourth command. The loop reads the last command, add, and the total becomes 3. Then next < 4 is false, and the loop ends by itself.
  4. Total 3. The line after the loop prints total 3: the quit command stopped nothing.
  5. break reading. CommandLoopFixed.java prints quit -> leaving the loop and runs break reading. reading is the label of the while loop, so the whole loop ends at once.
  6. Total 2. The line after the loop prints total 2, and the last add is never read. The arrow cases need no break of their own, so the only break left is the one that names the loop.

CommandLoop.java prints “leaving the switch” and then runs the fourth command anyway, ending with a total of 3. The fixed version labels the loop reading: and writes break reading;, so “quit” really stops the loop, at a total of 2. It also uses arrow labels, so the other cases need no break of their own; a plain break inside an arrow case would still end only the switch. Returning from a method, or a boolean that the loop condition tests, would work as well.

Checkpoint

Check: break inside a switch in a loop

  1. Question 1 of 2 CommandLoop.java gets the commands {"add", "quit", "add", "add"}. What total does it print after the loop?

    Type a number.

    A hint

    Which statement does the break in the quit case end?

    Show the answer: Question 1 of 2

    Answer: 3

    The break in the quit case ends only the switch, so the loop reads all four commands, and the three adds make the total 3. CommandLoopFixed.java would stop at quit with a total of 1.

  2. Question 2 of 2 Which change makes quit end the while loop of CommandLoop.java and still print the total after it?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Label the loop reading and write break reading; in the quit case

    A plain break in a switch ends the switch. To end the loop around it and carry on after the loop, the break must name the loop with a label.

The compiler refuses a break or continue with nowhere to go

The compiler catches the outright mistakes, each as a compile error: A message from the compiler that the code breaks a rule of the language, with the file, the line and the problem. A file with a compile error does not compile, so nothing of it runs. More in “IDEs, compiler errors and your first debug”: a break with no loop or switch around it, a continue whose label names a plain block rather than a loop, and a label that does not exist:

Three uses the compiler refuses

Java (BreakOutside.java) · BreakOutside.java

void main() {
    int count = 0;
    if (count == 0) {
        break;
    }
}

Java (LabelErrors.java) · LabelErrors.java

void main() {
    int count = 0;
    check: {
        if (count == 0) {
            continue check;
        }
    }
    for (int i = 0; i < 3; i++) {
        break outer;
    }
}

The session runs both files: after each $ comes the command, and below it what the compiler printed:

break outside a loop, and two label errors Python · errors_session.py
from session import run

run(
    """
java BreakOutside.java
java LabelErrors.java
""",
    fails=("java BreakOutside.java", "java LabelErrors.java"),
)

Output

# openjdk version "25.0.4.1" LTS
$ java BreakOutside.java
BreakOutside.java:4: error: break outside switch or loop
        break;
        ^
1 error
error: compilation failed
[exit status 1]
$ java LabelErrors.java
LabelErrors.java:5: error: not a loop label: check
            continue check;
            ^
LabelErrors.java:9: error: undefined label: outer
        break outer;
        ^
2 errors
error: compilation failed
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 errors_session.py

A label may stand before any statement, even a block, and break check; would leave that block. continue needs a loop to go on with, hence “not a loop label”. The rules fit in one table:

Statement Without a label With a label
break ends the innermost loop or switch; refused outside both ends the statement with that label, a block included
continue ends the current pass of the innermost loop goes on with the next pass of the labelled loop; refused for a block
Either (no label to check) refused when no statement around it carries the label

Checkpoint

Check: What the compiler refuses

  1. Question 1 of 2 javac reports undefined label: outer for a break outer;. What is wrong?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: No statement around the break carries the label outer

    The label of a labelled statement can only be used inside that statement. LabelErrors.java shows the message for a break outer; written in a loop that has no label at all.

  2. Question 2 of 2 A label stands before a block, check: { … }. Which statement inside the block does javac refuse?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: continue check;

    Any statement may carry a label, and break with the label ends it. continue with a label must name a while, do or for loop, as LabelErrors.java showed.

Practise: the first pair of cells with a sum

GridPairCheck.java asks for the first pair of different cells in a grid, read row by row, whose values add up to a target. The grid is an int[][], an array of rows: grid[r][c] is the value in row r and column c, and grid.length is the number of rows. Its first version only tries each cell with its right-hand neighbour, so three of its eight checks fail and it ends with exit status 1:

The checks against the first version Java · GridPairCheck.java
// Try it yourself: finish firstCellsWithSum() so that every check passes, then run java GridPairCheck.java.
//
// Read the cells of a rectangular grid row by row, left to right. Find the first pair of two different cells,
// a before b in that order, whose values add up to target: the pair whose first cell comes earliest, and with that
// first cell, the earliest second cell. Return {rowA, colA, rowB, colB}, or an empty array when there is no such pair.
int[] firstCellsWithSum(int[][] grid, int target) {
    // So far it only tries each cell with its right-hand neighbour.
    for (int r = 0; r < grid.length; r++) {
        for (int c = 0; c + 1 < grid[r].length; c++) {
            if (grid[r][c] + grid[r][c + 1] == target) {
                return new int[] {r, c, r, c + 1};
            }
        }
    }
    return new int[0];
}

int passed = 0;
int total = 0;

void check(String name, int[][] grid, int target, String expected) {
    total++;
    String got = Arrays.toString(firstCellsWithSum(grid, target));
    if (got.equals(expected)) {
        passed++;
        IO.println("PASS  " + name + ", target " + target + ": " + got);
    } else {
        IO.println("FAIL  " + name + ", target " + target + ": " + got + ", expected " + expected);
    }
}

void main() {
    int[][] small = {{3, 8, 1}, {5, 2, 7}};
    check("small", small, 9, "[0, 1, 0, 2]");
    check("small", small, 10, "[0, 0, 1, 2]");
    check("small", small, 7, "[1, 0, 1, 1]");
    check("small", small, 12, "[1, 0, 1, 2]");
    check("small", small, 100, "[]");
    check("one cell", new int[][] {{5}}, 10, "[]");
    check("square", new int[][] {{4, 6}, {6, 4}}, 10, "[0, 0, 0, 1]");
    check("columns", new int[][] {{2, 9}, {8, 1}}, 10, "[0, 0, 1, 0]");
    IO.println(passed + " of " + total + " checks pass");
    if (passed < total) {
        System.exit(1);
    }
}

Output (exit status 1)

PASS  small, target 9: [0, 1, 0, 2]
FAIL  small, target 10: [], expected [0, 0, 1, 2]
PASS  small, target 7: [1, 0, 1, 1]
FAIL  small, target 12: [], expected [1, 0, 1, 2]
PASS  small, target 100: []
PASS  one cell, target 10: []
PASS  square, target 10: [0, 0, 0, 1]
FAIL  columns, target 10: [], expected [0, 0, 1, 0]
5 of 8 checks pass

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java GridPairCheck.java

  1. Copy GridPairCheck.java and finish firstCellsWithSum().
  2. Run it with java GridPairCheck.java.
  3. You are done when the last line reads “8 of 8 checks pass”.

A first hint: number the cells 0, 1, 2 … in reading order; cell k of a grid with columns columns is in row k / columns and column k % columns. Two loops over those numbers, the second starting after the first, visit every pair in exactly the order the checks expect, and return stops both at the first match.

After the grid, go back over the seven ideas of the lesson, from the first break to the label rules. The practice below asks first about the statement you answer worst, and each choice explains itself when you pick it:

Practice that adapts to you

Practise this lesson

15 questions about 7 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 15 What does a plain break inside a for loop, and in no switch, do?

    Choose one answer.

    Show the answer: Question 1 of 15

    Answer: It ends the loop at once, and the statement after the loop runs next

    break transfers control to the innermost loop or switch around it, which then ends at once, so the program carries on with the statement after the loop.

  2. Question 2 of 15 The loop is meant to find the position of the first mark below 40. What does it print?

    Read the code, then choose one answer.

    int[] marks = {72, 35, 90, 28};
    int position = -1;
    for (int i = 0; i < marks.length; i++) {
        if (marks[i] < 40) {
            position = i;
        }
    }
    IO.println(position);
    Show the answer: Question 2 of 15

    Answer: 3

    This is the first loop of FirstAbove.java again: with no way to stop, the loop reports the last match instead of the first. Add break after position = i.

  3. Question 3 of 15 In a for loop, what runs right after a continue?

    Choose one answer.

    Show the answer: Question 3 of 15

    Answer: The update, then the test

    continue ends only the current pass. In a for loop the update i++ still runs, then the test decides whether there is another pass.

  4. Question 4 of 15 What does this print?

    Read the code, then choose one answer.

    for (int i = 1; i <= 6; i++) {
        if (i % 3 == 0) {
            continue;
        }
        IO.print(i + " ");
    }
    Show the answer: Question 4 of 15

    Answer: 1 2 4 5

    continue ends the current pass early. In a for loop the update i++ still runs before the next test, so the loop goes on with the next number. Only 3 and 6 are skipped.

  5. Question 5 of 15 In rows: for (…) { for (…) { if (found) break rows; } }, where does control go after break rows?

    Choose one answer.

    Show the answer: Question 5 of 15

    Answer: To the first statement after the outer loop

    A labelled break ends the statement with that label, here the outer loop, so execution continues after it. Java has no goto: a label never sends control back to the start.

  6. Question 6 of 15 The seat map is {"XXX", "X.X", "..."}. How many seat checks does the labelled search of FirstEmptySeat.java make, the check that finds the seat included?

    Type a number.

    Show the answer: Question 6 of 15

    Answer: 5 checks

    Row 0 has three booked seats, 3 checks. In row 1, seat 0 is booked and seat 1 is empty, 2 more checks, and break search ends both loops there: 3 + 2 = 5. Row 2 is never read.

  7. Question 7 of 15 What does continue rows; do inside the inner loop of rows: for (int r = 0; r < n; r++) { for (…) { … } }?

    Choose one answer.

    Show the answer: Question 7 of 15

    Answer: It ends the inner loop, runs r++ and goes on with the next pass of the outer loop

    continue rows abandons the inner loop and the rest of the outer loop's current pass. Because the outer loop is a for loop, its update r++ runs, and then its next test.

  8. Question 8 of 15 A loop over the 30 days of a month has a loop over the 24 hours of the day inside it. At the first hour with a power cut, the day must not be counted as clean, and the next day should start. The outer loop is labelled days. Which statement fits at the power cut?

    Choose one answer.

    Show the answer: Question 8 of 15

    Answer: continue days;

    This is the shape of EmptyRows.java: a check in the inner loop that disqualifies the whole outer item. continue with the outer loop's label skips straight to its next pass.

  9. Question 9 of 15 Why is firstEmptySeat() easier to follow than the labelled search?

    Choose one answer.

    Show the answer: Question 9 of 15

    Answer: return ends both loops and gives the answer as a value, with no label, flag or found variables

    A search with a name becomes a method whose return ends every loop and hands back the result, so the caller reads a value instead of following a label or a flag.

  10. Question 10 of 15 A program needs the first empty cell of a board in three different places. Which form fits best?

    Choose one answer.

    Show the answer: Question 10 of 15

    Answer: One method that returns the first empty cell, called in all three places

    When a search has a name, such as first empty cell, it is a method: return leaves every loop at once, and the callers get the answer as a value.

  11. Question 11 of 15 A plain break sits in a case of a switch statement, and the switch sits inside a while loop. What does the break end?

    Choose one answer.

    Show the answer: Question 11 of 15

    Answer: The switch, after which the loop goes on

    break ends the innermost switch, while, do or for statement around it. Inside a switch in a loop, that is the switch, as CommandLoop.java showed.

  12. Question 12 of 15 The list holds "go", "stop", "go". How many lines does this loop print?

    Read the code, then choose one answer.

    for (String s : List.of("go", "stop", "go")) {
        switch (s) {
            case "stop":
                break;
            default:
                IO.println(s);
        }
    }
    Show the answer: Question 12 of 15

    Answer: Two

    A break inside a switch statement leaves the switch, not the loop around it. The loop goes on with the third item and prints "go" again, so two lines appear. To leave the loop, label it and write break with the label, or return from a method.

  13. Question 13 of 15 What does this print?

    Read the code, then choose one answer.

    int total = 0;
    for (String s : List.of("add", "quit", "add")) {
        switch (s) {
            case "add" -> total++;
            case "quit" -> {
                break;
            }
            default -> IO.println("unknown " + s);
        }
    }
    IO.println(total);
    Show the answer: Question 13 of 15

    Answer: 2

    Arrow labels stop fall-through, but a plain break inside a case block still ends only the switch. That is why CommandLoopFixed.java needs break reading to leave the loop.

  14. Question 14 of 15 Where may break search; stand?

    Choose one answer.

    Show the answer: Question 14 of 15

    Answer: Anywhere inside the statement labelled search, however deeply nested

    A label can be used only inside the statement it labels. From anywhere in there, break search ends that whole statement.

  15. Question 15 of 15 Which of these does not compile?

    Choose one answer.

    Show the answer: Question 15 of 15

    Answer: check: { if (x < 0) continue check; IO.println(x); }

    Any statement may carry a label, and break with that label leaves it, even a plain block. continue needs a loop to go on with, so continue check on a block is refused with "not a loop label: check".

Interview questions

Fresher · What is the difference between break and continue in a Java loop?

break ends the innermost loop or switch around it at once, and execution carries on with the statement after it. continue ends only the current pass of the innermost loop: a while or do-while loop goes straight to its condition, and a for loop runs its update first, then its condition. Both take an optional label to act on an outer statement instead: break outer; leaves the loop labelled outer, and continue outer; goes on with that loop’s next pass. A plain break inside a switch leaves only the switch, not the loop around it. A common bug is a continue in a while loop that skips the update at the bottom of the body, so the loop never moves on.

Interviewers like to follow this answer with a loop that misbehaves. Here are two such loops: decide what each one does, then see why every other option is wrong:

Checkpoint

Interview round: two follow-up questions

  1. Question 1 of 2 A loop ships orders: for (String s : status) { switch (s) { case "CANCELLED": break; default: shipped++; } }. The statuses are PAID, PAID, CANCELLED and PAID, and its author meant shipping to stop at the cancelled order. What does shipped end at?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 3, because the break ends the switch and the loop goes on with the fourth order

    The code skips cancelled orders instead of stopping at the first one. To stop, label the loop and break with the label, or move the loop into a method and return. To skip, as it does now, continue in that case says so more plainly: inside a switch in a loop, continue goes on with the loop's next pass.

  2. Question 2 of 2 What does this do?

    Read the code, then choose one answer.

    int i = 0;
    do {
        if (i == 2) {
            continue;
        }
        IO.print(i + " ");
        i++;
    } while (i < 5);
    Show the answer: Question 2 of 2

    Answer: It prints 0 1, and then the loop never ends

    After a continue, a do statement evaluates its condition, as the language specification says for the do statement. Like a while loop, it has no separate update, so an update below the continue is skipped.

Two longer questions of this module build on this lesson: a worker thread that sits at full CPU after a deploy, and a three-level seat search full of flags and a labelled break.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    After a deploy, one worker thread of a service sits at 100 % of a CPU core and its queue stops draining. You suspect a loop that never ends. How do you confirm it, find the line, stop the damage and prevent this kind of bug?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    Reading a colleague's change, you find a method that searches a stadium plan (levels × rows × seats) for the first block of k adjacent empty seats, using three nested loops, two boolean flags and a labelled break. How would you restructure it, and what does the search cost in the worst case?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • break ends the innermost loop or switch at once, so a search that breaks at its first match keeps that match instead of carrying a flag to the next test.
  • continue ends the current pass: a for loop still runs its update, while a while or do-while loop goes straight to its condition, so a continue above i++ can loop for ever.
  • A label such as search: lets break search; end an outer loop and continue search; go on with its next pass, where a plain continue would only move to the next item of the inner loop.
  • When a nested search has a name, write it as a method: return ends every loop at once and hands back the answer.
  • A break inside a switch ends the switch, not the loop around it, so label the loop or return.
  • The compiler refuses a break outside any loop or switch, a continue whose label names a block, and a label that no statement around it carries.

Terms in this lesson

flag
A boolean variable that records that something has happened, such as found = true, so that a later test, often the loop condition, can act on it. A break or a return usually says the same thing more directly.
label
A name and a colon written before a statement, as in search: for (…). Inside that statement, break search; ends it, and continue search; goes on with its next pass when the statement is a loop. Java has no goto, so a label is used only this way.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.