Most loops you have written so far run from start to finish, touching every element. That is fine for adding up a list, but real programs constantly need to stop early or skip ahead. A login form scans a list of users and should stop the instant it finds a match — there is no point checking the rest. A report loop should jump past weekends when totalling daily sales. Telling a loop to leave early, or to step past an item, is the difference between code that does exactly enough work and code that wastes time.
Java gives you two keywords for this: break exits the loop entirely, and continue abandons the current iteration and moves to the next one. Both look tiny, but they change the path a program takes — so predicting their effect is a core reading skill.
flowchart TD
N["start of an iteration"] --> C{"should we<br/>break or continue?"}
C -->|"break"| X["leave the loop<br/>immediately"]
C -->|"continue"| S["skip the rest<br/>go to next item"]
C -->|"neither"| R["run the rest<br/>of the body"]
R --> S
style X fill:#b45309,color:#fff
style S fill:#166534,color:#fff
break: leave the loop now
When Java reaches break, it immediately exits the nearest enclosing loop — no more iterations, no more body, no condition check. Control jumps to the statement right after the loop. The classic use is a search that stops on the first hit: you do not need a boolean flag, because break already says stop.
for (int n : nums) {
if (n == target) {
System.out.println("found");
break;
}
}
Whatever comes after the loop runs next, exactly once. Note what break does not do: it does not return a value, and it does not unwind more than one loop. In a nested structure, break only escapes the innermost loop it sits inside — a detail that quietly becomes a bug, as you will see below.
public class Main {
public static void main(String[] args) {
int[] nums = {4, 8, 15, 16, 23};
int target = 15;
int index = -1;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == target) {
index = i;
break;
}
}
System.out.println("found at index " + index);
}
}
continue: skip this one, go to the next
continue is the gentler sibling. It abandons the rest of the current iteration and jumps straight to the next one — the loop itself keeps going. Reach for it when most of the body should run, but some items need to be passed over.
There is a subtlety about where continue jumps, and it depends on the loop type. In a for loop, continue jumps to the update step (the i++ part), so the counter still advances and the loop progresses. In a while loop there is no hidden update, so continue jumps straight to the condition — and if you have not already advanced your counter on the line above, the loop runs forever. This is why continue feels safe inside for loops and dangerous inside while loops.
public class Main {
public static void main(String[] args) {
int total = 0;
for (int i = 1; i <= 5; i++) {
if (i % 2 == 0) {
continue;
}
total = total + i;
}
System.out.println("sum of odds: " + total);
}
}
flowchart TD
subgraph OUTER["outer loop"]
subgraph INNER["inner loop"]
I["iteration"] --> T{"break?"}
T -->|"yes"| B["break exits<br/>inner loop only"]
T -->|"no"| W["run the body"]
W --> I
end
B --> NXT["outer loop<br/>moves to next i"]
end
style B fill:#b45309,color:#fff
The classic trap: break only leaves the nearest loop
Drop a break inside a loop that is itself inside another loop, and the break exits only the inner loop. The outer loop is completely unaffected — it happily moves to its next iteration and starts the inner loop over again. This is the single most common surprise with break, and it is not a bug in Java; it is the rule.
If you actually need to leave both loops at once — say you are searching a grid and found your cell — an ordinary break will not do it. The inner loop ends, the outer loop continues, and your search re-scans the next row. Recognising this gap is what leads to the next idea: labels.
flowchart TD
L["label<br/>outer"] --> O["outer loop"]
O --> I["inner loop"]
I --> D{"break outer?"}
D -->|"yes"| OUT["leave both loops"]
D -->|"no"| M["keep searching"]
M --> I
style L fill:#3776ab,color:#fff
style OUT fill:#b45309,color:#fff
Labels: break out of a chosen loop
When you need a break or continue to reach past the nearest loop, Java lets you name a loop with a label and aim at it. A label is an identifier followed by a colon, placed just before the loop.
outer:
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == target) {
break outer; // leaves BOTH loops
}
}
}
break outer exits the loop named outer, no matter how many loops are nested inside it. continue outer works the same way: it skips to the next iteration of the labelled loop, jumping over every inner loop in between. Labels are rare in everyday Java because most code is better restructured into a method that simply returns — but when you do need them, nothing else expresses the intent as clearly.
Use them sparingly
Both keywords are tools, not habits. A loop with a break buried in the middle is harder to reason about than one whose stopping rule sits at the top, because the real exit condition is now scattered across the body. The same is true of continue: stack two or three in one loop, and a reader can no longer see the happy path through the guards.
Reach for break when a search has clearly finished, and for continue when a guard at the top of the body saves a whole level of indentation. If you are chaining four continue statements, invert the condition or extract the body into its own method. Readability is a feature, not a nicety.
break stops the sum early. Predict the exact output (two lines) — the loop abandons its work the moment it hits 9.
public class Main {
public static void main(String[] args) {
int[] nums = {3, 7, 2, 9, 4};
int sum = 0;
for (int n : nums) {
if (n == 9) {
break;
}
sum = sum + n;
}
System.out.println(sum);
System.out.println(nums[0]);
}
}
n takes the values 3, 7, 2, then 9 in turn.
When n is 9 the break fires BEFORE 9 is added, so sum stays at 3 + 7 + 2 = 12.
nums[0] is 3, and it is printed after the loop no matter what.
continue skips the evens. Predict the exact output (two lines) — odd numbers are added, even ones are passed over.
public class Main {
public static void main(String[] args) {
int sum = 0;
int count = 0;
for (int i = 1; i <= 6; i++) {
if (i % 2 == 0) {
continue;
}
sum = sum + i;
count = count + 1;
}
System.out.println(sum);
System.out.println(count);
}
}
continue jumps to the update i++, so i still advances — only the rest of THIS pass is skipped.
The odd values 1, 3, 5 are added: sum = 1 + 3 + 5 = 9, and count = 3.
The even values 2, 4, 6 hit continue before the sum and count lines, so they contribute nothing.
Inside a for loop, what happens immediately after continue runs?
continue abandons the remaining statements of the current pass but does NOT exit the loop. In a for loop it jumps to the update step, so the counter still advances and the loop progresses. In a while loop there is no hidden update, so continue jumps to the condition — forgetting to advance the counter first causes an infinite loop.
The nested-loop trap. A break sits inside an inner loop. Predict the exact output (three lines) — remember which loop the break actually leaves.
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
break;
}
System.out.println(i + "," + j);
}
}
}
}
For each value of i, the inner loop runs j = 1 first.
j = 1 is not 2, so it prints i,1. Then j becomes 2, the break fires, and the INNER loop ends.
break only leaves the inner loop, so the outer loop moves on to the next i — which is why all three rows appear.
Labelled break transfer. The inner loop hunts for a 0 and then breaks the OUTER loop by name. Predict the exact output (two lines).
public class Main {
public static void main(String[] args) {
int[][] grid = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 0}
};
int foundRow = -1;
int foundCol = -1;
outer:
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c] == 0) {
foundRow = r;
foundCol = c;
break outer;
}
}
}
System.out.println(foundRow);
System.out.println(foundCol);
}
}
The 0 lives at grid[2][2] — row 2, column 2 (both zero-based).
When it is found, foundRow and foundCol are set, then break outer fires.
break outer leaves BOTH loops at once, so the search stops immediately and the two values are printed.
Recap
breakexits the nearest enclosing loop immediately; the statement after the loop runs next.continueskips the rest of the current iteration and moves to the next one. In aforloop it still runs the update step; in awhileloop it jumps to the condition.- In nested loops,
breakandcontinueaffect only the innermost loop unless you label an outer one. - A label (
name:) before a loop letsbreak outerandcontinue outertarget a specific loop, escaping every loop nested inside it.
Next you will put these flow keywords to work on arrays — Java's fixed-length, indexed collections — where stopping early and skipping ahead become genuinely useful.