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.
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:
// 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:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- 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.
- Passes 2 and 3. 41 and 39 are not above 45 either. After three passes, and three readings looked at, i is 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.
- 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.
- 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.
- 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
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:
// 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:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
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 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:
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:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
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:
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:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- 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.
- 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.
- 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.
- 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.
- 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
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.
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:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- The call. main calls firstEmptySeat(), and the method's two loops start on row 0.
- 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.
- 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.
- 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.
- main prints it. main prints method with return: row 1, seat 3, the same answer as the labelled break gave.
- 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
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:
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:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- Two adds. Both versions read add twice, and each add case adds 1, so both totals are 2 when the quit command comes.
- 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.
- 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.
- Total 3. The line after the loop prints total 3: the quit command stopped nothing.
- 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.
- 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
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:
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:
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
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:
// 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
- Copy
GridPairCheck.javaand finishfirstCellsWithSum(). - Run it with
java GridPairCheck.java. - 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.
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
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.
-
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?
-
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?
Key takeaways
breakends 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.continueends the current pass: aforloop still runs its update, while awhileordo-whileloop goes straight to its condition, so acontinueabovei++can loop for ever.- A label such as
search:letsbreak search;end an outer loop andcontinue search;go on with its next pass, where a plaincontinuewould only move to the next item of the inner loop. - When a nested search has a name, write it as a method:
returnends every loop at once and hands back the answer. - A
breakinside aswitchends the switch, not the loop around it, so label the loop or return. - The compiler refuses a
breakoutside any loop or switch, acontinuewhose 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
- The Java Language Specification, Java SE 25: 14.15 The break Statement (Oracle)
- The Java Language Specification, Java SE 25: 14.16 The continue Statement (Oracle)
- The Java Language Specification, Java SE 25: 14.7 Labeled Statements (Oracle)
- The Java Language Specification, Java SE 25: 14.14.1.3 Abrupt Completion of for Statement (Oracle)
- The Java Language Specification, Java SE 25: 14.13 The do Statement (Oracle)
- Learn Java: Control Flow Statements (Oracle)
Report a problem with this lesson
Kept only in this browser. Your Learn progress