Java Continue
The continue statement skips the rest of the current loop iteration and moves straight to the next one. Unlike break, the loop does not end; only the remaining statements in this pass are skipped. It is used to filter out items that should not be processed, without wrapping the main logic in a large if block.
continue in a for Loop
for (int i = 1; i <= 6; i++) {
if (i % 2 == 0) {
continue;
}
System.out.println(i);
}
Output:
1
3
5
When i is even, continue skips the println. In a for loop, control then goes to the update (i++) and then to the condition, exactly as if the body had finished normally. The loop runs all six iterations; only the even ones produce no output.
continue in while and do-while
In a while or do-while loop, continue jumps directly to the condition. Any update that sits at the bottom of the body is skipped too, which can create an infinite loop:
int i = 0;
while (i < 6) {
if (i % 2 == 0) {
continue; // i++ below is never reached when i is even
}
System.out.println(i);
i++;
}
// i stays 0 forever
The fix is to update the loop variable before any continue can run:
int i = 0;
while (i < 6) {
i++;
if (i % 2 == 0) {
continue;
}
System.out.println(i);
}
Output:
1
3
5
This difference is one reason for loops are safer for counting: the update lives in the header and runs even after continue.
| Loop | Where continue jumps |
|---|---|
for | To the update, then the condition |
Enhanced for | To the next element |
while | To the condition |
do-while | To the condition at the bottom |
Skipping Invalid Data
continue is most useful as an early filter at the top of a loop body. Each unwanted case is rejected in one line, and the main processing stays unindented:
String[] lines = {"42", "", "17", "# comment", "abc", "8"};
int sum = 0;
for (String line : lines) {
line = line.strip();
if (line.isEmpty()) {
continue; // skip blank lines
}
if (line.startsWith("#")) {
continue; // skip comments
}
try {
sum += Integer.parseInt(line);
} catch (NumberFormatException e) {
System.out.println("Skipping invalid value: " + line);
}
}
System.out.println("Sum: " + sum);
Output:
Skipping invalid value: abc
Sum: 67
Compare the same logic without continue:
for (String line : lines) {
line = line.strip();
if (!line.isEmpty()) {
if (!line.startsWith("#")) {
// main logic, indented two levels deeper
}
}
}
Both work. With several filters, the continue version stays flat and lists each rejection rule separately, which reads more like the rules themselves.
continue Versus break
int[] values = {3, -1, 7, -4, 5};
System.out.print("continue: ");
for (int v : values) {
if (v < 0) continue;
System.out.print(v + " ");
}
System.out.println();
System.out.print("break: ");
for (int v : values) {
if (v < 0) break;
System.out.print(v + " ");
}
System.out.println();
Output:
continue: 3 7 5
break: 3
continue skips the negative numbers and keeps going. break stops at the first negative number and ignores everything after it.
Labeled continue
In nested loops, a plain continue affects only the innermost loop. A labeled continue skips to the next iteration of an outer loop:
String[] words = {"apple", "sky", "rhythm", "tree"};
outer:
for (String word : words) {
for (char c : word.toCharArray()) {
if ("aeiou".indexOf(c) >= 0) {
System.out.println(word + " has a vowel");
continue outer;
}
}
System.out.println(word + " has no vowels");
}
Output:
apple has a vowel
sky has no vowels
rhythm has no vowels
tree has a vowel
As soon as a vowel is found, continue outer abandons the inner character loop and skips the "no vowels" line, moving straight to the next word. With a plain continue, the inner loop would just move to the next character. The "no vowels" message runs only when the inner loop finishes without finding one.
As with labeled break, moving the inner loop into a helper method (boolean hasVowel(String word)) often makes the code clearer than a label.
Practical Example: Processing Orders
import java.util.List;
public class OrderProcessor {
record Order(String id, String status, double amount, String country) {}
public static void main(String[] args) {
List<Order> orders = List.of(
new Order("A1", "PAID", 1200, "IN"),
new Order("A2", "CANCELLED", 800, "IN"),
new Order("A3", "PAID", 0, "IN"),
new Order("A4", "PAID", 450, "US"),
new Order("A5", "PAID", 3000, "IN")
);
double revenue = 0;
int processed = 0;
for (Order o : orders) {
if (!o.status().equals("PAID")) {
continue; // only paid orders
}
if (o.amount() <= 0) {
System.out.println("Warning: " + o.id() + " has no amount");
continue; // data problem; skip
}
if (!o.country().equals("IN")) {
continue; // domestic report only
}
revenue += o.amount();
processed++;
System.out.println("Processed " + o.id());
}
System.out.printf("%d orders, revenue %.2f%n", processed, revenue);
}
}
Output:
Processed A1
Warning: A3 has no amount
Processed A5
2 orders, revenue 4200.00
Each continue expresses one business rule. Orders that are not paid, have no amount, or are international are skipped, and the main processing at the bottom runs only for orders that pass every rule. A new rule can be added as another two-line guard without restructuring the loop. The record declares a compact data class; records have their own lesson in the OOP section.