Skip to main content

4.3 Control Flow Statements

To regulate loops, Java provides special keywords for directly controlling the flow of execution. Using break, continue, and return, you can dynamically adjust iteration counts and immediately terminate methods.

1. break Statement

When a break statement is encountered, it completely exits the nearest enclosing loop (or switch statement).

Basic Usage

// Find the point where the sum first exceeds 100
int sum = 0;
int i = 0;

while (true) { // infinite loop
i++;
sum += i;
if (sum > 100) {
break; // exit the loop when the condition is met
}
}
System.out.println("i = " + i + ", sum = " + sum);
// Output: i = 14, sum = 105

break in a for Loop

int[] numbers = {3, 7, 1, 9, 5, 2, 8};
int target = 9;
int foundIndex = -1;

for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == target) {
foundIndex = i;
break; // no need to keep iterating once found
}
}

if (foundIndex != -1) {
System.out.println(target + " found at index " + foundIndex + ".");
} else {
System.out.println(target + " was not found.");
}
// Output: 9 found at index 3.

2. Labeled break

In nested loops, break by default exits only the nearest enclosing loop. Using a label, you can exit all the way to an outer loop in a single step.

Limitation of Unlabeled break

// Without a label, only the inner loop is exited
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
break; // exits only the inner for loop; the outer loop continues
}
System.out.println("i=" + i + ", j=" + j);
}
}
// Even when i==1, j==1, the iteration for i==2 still runs

Labeled break to Exit Nested Loops

// Labeled break: exits all the way to the labeled outer loop
outer: // label declaration (lowercase by convention)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
break outer; // exits the for loop labelled 'outer'
}
System.out.println("i=" + i + ", j=" + j);
}
}
System.out.println("Completely exited the loop");

Output:

i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
Completely exited the loop

Practical Use: Searching a 2D Array

public class SearchIn2DArray {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int target = 7;
int row = -1, col = -1;

search:
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == target) {
row = i;
col = j;
break search; // exit both loops once found
}
}
}

if (row != -1) {
System.out.printf("Value %d found at [%d][%d].%n", target, row, col);
}
// Output: Value 7 found at [1][2].
}
}

3. continue Statement

When a continue statement is encountered, the remaining code in the current iteration is skipped and execution jumps directly to the next iteration. Unlike break, it does not exit the loop.

Basic Usage

// Print only odd numbers from 1 to 10
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // skip the print statement below for even numbers
}
System.out.print(i + " "); // only executes for odd numbers
}
// Output: 1 3 5 7 9

Detailed Behavior of continue

for (int i = 0; i <= 5; i++) {
System.out.print("start(" + i + ") ");
if (i == 3) {
continue; // skip the "end" print when i==3
}
System.out.print("end(" + i + ") ");
}

Output:

start(0) end(0) start(1) end(1) start(2) end(2) start(3) start(4) end(4) start(5) end(5)

"end(3)" is not printed because continue skips it when i=3.

Caution with continue in a while Loop

// Note: when using continue in a while loop, place the increment before continue
int i = 0;
while (i < 10) {
i++; // increment first!
if (i % 2 == 0) {
continue; // skip even numbers; no infinite loop since increment is above
}
System.out.print(i + " ");
}
// Output: 1 3 5 7 9
while + continue Infinite Loop Risk
int i = 0;
while (i < 10) {
if (i % 2 == 0) {
continue; // when i is 0, continue -> check condition -> i is still 0 -> infinite loop!
}
i++;
}

The increment is never reached after continue, causing an infinite loop. Pay close attention to where the increment is placed in while loops.

4. Labeled continue

Using a label, you can jump to the next iteration of an outer loop from a nested loop.

outer:
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (j == 2) {
continue outer; // skip the inner loop and move to the next iteration of outer (i++)
}
System.out.print("[" + i + "," + j + "] ");
}
System.out.println(); // this line never runs because of continue outer
}

Output:

[0,0] [0,1] [1,0] [1,1] [2,0] [2,1] [3,0] [3,1]

5. return Statement

The return statement immediately terminates the currently executing method. It is useful when a method needs to exit early based on a condition.

return in a void Method

public class ReturnExample {
// In a void method, return is used alone without a value
static void printPositive(int number) {
if (number <= 0) {
System.out.println("Not a positive number.");
return; // immediately terminates the method
}
// Only reaches here if number is positive
System.out.println("Positive: " + number);
}

public static void main(String[] args) {
printPositive(5); // Output: Positive: 5
printPositive(-3); // Output: Not a positive number.
printPositive(10); // Output: Positive: 10
}
}

return in a Method with a Return Value

// Method that returns the larger of two numbers
static int max(int a, int b) {
if (a > b) {
return a; // if a is larger, return a immediately and exit
}
return b; // otherwise return b
}

// Reducing nesting with early return pattern
static String getGrade(int score) {
if (score < 0 || score > 100) return "Error"; // validation
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
if (score >= 60) return "D";
return "F";
}

6. Practical Example 1: Printing Prime Numbers (Using break/continue)

public class PrimeList {
public static void main(String[] args) {
int limit = 30;
System.out.print("Primes up to " + limit + ": ");

for (int n = 2; n <= limit; n++) {
boolean isPrime = true;

for (int i = 2; i * i <= n; i++) { // check up to sqrt(n)
if (n % i == 0) {
isPrime = false;
break; // divisor found: no further checking needed, exit inner loop
}
}

if (!isPrime) {
continue; // skip printing if not prime
}
System.out.print(n + " ");
}
System.out.println();
}
}

Output:

Primes up to 30: 2 3 5 7 11 13 17 19 23 29

7. Practical Example 2: Number Guessing Game (break + Scanner)

import java.util.Random;
import java.util.Scanner;

public class NumberGuessingGame {
public static void main(String[] args) {
Random random = new Random();
Scanner scanner = new Scanner(System.in);

int answer = random.nextInt(100) + 1; // random number from 1 to 100
int attempts = 0;
int maxAttempts = 10;

System.out.println("Guess a number between 1 and 100! (max " + maxAttempts + " attempts)");

while (attempts < maxAttempts) {
System.out.print("Guess: ");
int guess = scanner.nextInt();
attempts++;

if (guess < 1 || guess > 100) {
System.out.println("Please enter a number between 1 and 100.");
attempts--; // invalid input does not count
continue;
}

if (guess == answer) {
System.out.println("Correct! You got it in " + attempts + " attempt(s)!");
break; // exit the loop on correct answer
} else if (guess < answer) {
System.out.println("Too low. Remaining attempts: " + (maxAttempts - attempts));
} else {
System.out.println("Too high. Remaining attempts: " + (maxAttempts - attempts));
}
}

if (attempts >= maxAttempts) {
System.out.println("Game over! The answer was " + answer + ".");
}

scanner.close();
}
}

Sample run:

Guess a number between 1 and 100! (max 10 attempts)
Guess: 50
Too low. Remaining attempts: 9
Guess: 75
Too high. Remaining attempts: 8
Guess: 63
Correct! You got it in 3 attempt(s)!
Pro Tips

Control Flow Statement Principles:

  1. break for a clear termination condition— always document the break condition when exiting an infinite loop.
  2. continue is useful for filtering— skipping items that do not match a condition is clearer with continue than with nested if blocks.
  3. Labels as a last resort— labels hurt readability. Extracting the logic into a method is usually better.
  4. Reduce nesting with early return— handle invalid cases with return at the start of the method to reduce nesting depth.
// Heavily nested approach
void process(String input) {
if (input != null) {
if (!input.isEmpty()) {
if (input.length() > 3) {
// actual processing
}
}
}
}

// Improved with early return
void process(String input) {
if (input == null) return;
if (input.isEmpty()) return;
if (input.length() <= 3) return;
// actual processing
}