Java flow control
Last modified October 13, 2026 Java 25
In this article we cover program flow control in Java. We show conditional
statements, the switch statement and expression including pattern
matching, loops, and the break and continue
statements.
Control flow statements
By default, the statements of a method are executed one by one, from top to bottom. Control flow statements alter this order: they execute code only under a specific condition, repeat it multiple times, or jump out of it.
if,else, andswitchchoose between alternative branches.while,do while, andforcreate loops.break,continue,yield, andreturntransfer control elsewhere.
The examples use compact source files with an instance main
method, which are final since Java 25. Programs that read user input use the
IO.readln method, also new in Java 25.
The if statement
The if statement has the following general form:
if (expression) {
statement;
}
The if keyword checks whether a boolean expression is true. If it
is, the statement that follows is executed. The statement can be a single
statement or a block. A block is a sequence of statements enclosed in curly
brackets. The brackets are optional if the body has only one statement, but
using them always is a widely followed convention that prevents mistakes when
statements are added later.
import java.util.Random;
void main() {
var r = new Random();
int num = r.nextInt(-10, 11);
if (num > 0) {
System.out.println("The number is positive");
}
}
A random number is generated. If the number is greater than zero, we print a message to the terminal.
var r = new Random(); int num = r.nextInt(-10, 11);
These two lines generate a random integer between -10 and 10. The second
argument of nextInt is exclusive.
if (num > 0) {
System.out.println("The number is positive");
}
The if keyword is followed by an expression in round brackets. The
expression must evaluate to a boolean value; unlike in C, an
integer is not accepted. If the value is true, the block is executed. If the
number is zero or negative, nothing is printed.
$ java Main.java The number is positive $ java Main.java $ java Main.java The number is positive
The else keyword
We can use the else keyword to create a simple branch. If the
expression in the round brackets following the if keyword
evaluates to false, the statement following the else keyword is
executed.
import java.util.Random;
void main() {
var r = new Random();
int num = r.nextInt(-10, 11);
if (num > 0) {
System.out.println("The number is positive");
} else {
System.out.println("The number is zero or negative");
}
}
Exactly one of the two blocks is executed: either the block following the
if keyword or the block following the else keyword.
$ java Main.java The number is zero or negative $ java Main.java The number is positive $ java Main.java The number is zero or negative
Multiple branches with else if
We can create multiple branches with else if. Each
else if tests another condition if and only if all previous
conditions were false. We can chain as many else if branches as
needed.
The previous program could not tell zero from negative numbers. The following program handles the three cases separately.
void main() {
String input = IO.readln("Enter an integer: ");
int num = Integer.parseInt(input.trim());
if (num < 0) {
System.out.println("The integer is negative");
} else if (num == 0) {
System.out.println("The integer is zero");
} else {
System.out.println("The integer is positive");
}
}
We read a value from the user and test whether it is negative, zero, or positive.
String input = IO.readln("Enter an integer: ");
int num = Integer.parseInt(input.trim());
The IO.readln method prints a prompt and reads a line from the
standard input. We convert the line to an integer with
Integer.parseInt, which throws a
NumberFormatException if the text is not a valid number.
if (num < 0) {
System.out.println("The integer is negative");
} else if (num == 0) {
System.out.println("The integer is zero");
} else {
System.out.println("The integer is positive");
}
If the first condition is true, that is, the entered value is less than zero,
the first block is executed and the remaining two blocks are skipped. Otherwise
the condition following else if is checked. If it is true, the
second block is executed. If neither condition is met, the block following
else is executed.
$ java Main.java Enter an integer: 4 The integer is positive $ java Main.java Enter an integer: 0 The integer is zero $ java Main.java Enter an integer: -3 The integer is negative
The conditional operator
When an if else statement only chooses between two values, the
conditional (ternary) operator ?: is a more compact alternative.
It is an expression, so its result can be assigned directly.
void main() {
int age = 17;
String status = age >= 18 ? "adult" : "minor";
System.out.println(status);
}
If the condition before ? is true, the expression evaluates to the
value after ?; otherwise it evaluates to the value after
:.
$ java Main.java minor
The switch statement
The switch statement is a multi-way branch. It compares a value
against a list of constants, each introduced by the case keyword,
and executes the code of the matching case. The optional default
label is executed if no other case matches. A switch is often
clearer than a long chain of if and else if
statements.
void main() {
String domain = IO.readln("Enter a domain: ").trim().toLowerCase();
switch (domain) {
case "us":
System.out.println("United States");
break;
case "de":
System.out.println("Germany");
break;
case "sk":
System.out.println("Slovakia");
break;
case "hu":
System.out.println("Hungary");
break;
default:
System.out.println("Unknown");
break;
}
}
The user is asked to enter a country code top-level domain. The program prints the name of the matching country.
String domain = IO.readln("Enter a domain: ").trim().toLowerCase();
The trim method removes leading and trailing whitespace and
toLowerCase converts the characters to lowercase. This way,
"us", "US", and " us " all match the same case.
switch (domain) {
...
}
The value to be tested is placed in round brackets after the
switch keyword. With constant case labels, it can be of type
char, byte, short, int,
their wrapper classes, String, or an enum type. With pattern
matching, shown later, any reference type can be used.
case "us":
System.out.println("United States");
break;
If domain equals "us", the message is printed. The
break statement then exits the switch. Without it,
execution would fall through to the statements of the next case, which
is a common source of bugs.
default:
System.out.println("Unknown");
break;
The default section is executed if none of the cases matches.
$ java Main.java Enter a domain: us United States
Fall-through is occasionally used on purpose to share code among several cases.
void main() {
int month = 4;
switch (month) {
case 12:
case 1:
case 2:
System.out.println("Winter");
break;
case 3:
case 4:
case 5:
System.out.println("Spring");
break;
default:
System.out.println("Summer or autumn");
}
}
The empty cases 3 and 4 fall through to the statements of case 5.
$ java Main.java Spring
Arrow labels
Since Java 14, case labels can use the arrow form case ... ->.
An arrow case executes only the expression, block, or throw
statement on its right side; there is no fall-through, so no
break is needed. Several constants can share one case, separated
by commas.
void main() {
String domain = IO.readln("Enter a domain: ").trim().toLowerCase();
switch (domain) {
case "us" -> System.out.println("United States");
case "de" -> System.out.println("Germany");
case "sk" -> System.out.println("Slovakia");
case "hu" -> System.out.println("Hungary");
default -> System.out.println("Unknown");
}
}
This is the domain example rewritten with arrow labels. It is still a
switch statement; it only performs actions and produces no value.
$ java Main.java Enter a domain: sk Slovakia
The switch expression
A switch expression evaluates to a value, which can be assigned to a variable,
returned, or passed to a method. Unlike a switch statement, a switch expression
must be exhaustive: every possible input value must be covered, usually
with a default case.
void main() {
String domain = IO.readln("Enter a domain: ").trim().toLowerCase();
String country = switch (domain) {
case "us" -> "United States";
case "de" -> "Germany";
case "sk" -> "Slovakia";
case "hu" -> "Hungary";
default -> "Unknown";
};
System.out.println(country);
}
Each case now yields a string, and the result of the whole
switch is assigned to the country variable. Note the
semicolon after the closing curly bracket; it ends the assignment statement.
$ java Main.java Enter a domain: hu Hungary $ java Main.java Enter a domain: xx Unknown
When a case needs more than a single expression, we use a block and return the
value with the yield statement.
import java.time.DayOfWeek;
import java.time.LocalDate;
void main() {
DayOfWeek day = LocalDate.of(2026, 10, 13).getDayOfWeek();
String type = switch (day) {
case SATURDAY, SUNDAY -> "weekend";
case FRIDAY -> {
System.out.println("Almost there...");
yield "workday";
}
default -> "workday";
};
System.out.printf("%s is a %s%n", day, type);
}
We switch on an enum value. The SATURDAY and SUNDAY
constants share one case. Enum constants in case labels are written without
the type name.
$ java Main.java TUESDAY is a workday
Pattern matching in switch
Since Java 21, case labels can contain type patterns and record patterns. A
case matches if the value has the given type, and the pattern variables are
bound to the value or its components. An optional when clause,
called a guard, adds an extra condition. Combined with a sealed interface, the
compiler knows all possible types and can check exhaustiveness without a
default case.
sealed interface Shape permits Circle, Square, Rectangle {}
record Circle(double radius) implements Shape {}
record Square(double side) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
String describe(Shape shape) {
return switch (shape) {
case Circle c -> "circle, area %.2f".formatted(Math.PI * c.radius() * c.radius());
case Square s -> "square, area %.2f".formatted(s.side() * s.side());
case Rectangle(double w, double h) when w == h -> "rectangle with equal sides";
case Rectangle(double w, double h) -> "rectangle, area %.2f".formatted(w * h);
};
}
void main() {
List<Shape> shapes = List.of(new Circle(1.5), new Square(3),
new Rectangle(2, 5), new Rectangle(4, 4));
for (Shape shape : shapes) {
System.out.println(describe(shape));
}
}
The describe method returns a different description for each kind
of shape.
case Circle c -> "circle, area %.2f".formatted(Math.PI * c.radius() * c.radius());
The type pattern Circle c matches if the shape is a
Circle; the c variable then holds the shape as a
Circle, so no cast is needed.
case Rectangle(double w, double h) when w == h -> "rectangle with equal sides"; case Rectangle(double w, double h) -> "rectangle, area %.2f".formatted(w * h);
The record pattern Rectangle(double w, double h) deconstructs the
record into its components. The first case is guarded, so it only matches
rectangles with equal sides. Cases are tested from top to bottom, which is why
the guarded case must come before the general one.
$ java Main.java circle, area 7.07 square, area 9.00 rectangle, area 10.00 rectangle with equal sides
The while statement
The while statement executes a block repeatedly as long as a
boolean condition is true. The condition is tested before each iteration, so
the body may not run at all.
while (expression) {
statement;
}
void main() {
int i = 0;
int sum = 0;
while (i < 10) {
i++;
sum += i;
}
System.out.println(sum);
}
The example calculates the sum of the integers from 1 to 10.
A counting while loop typically has three parts: initialization,
testing, and updating. Each execution of the body is called an iteration.
int i = 0;
We initialize the i variable. It is used as a counter.
while (i < 10) {
...
}
The expression inside the round brackets is the test. The statements in the body are executed until the expression evaluates to false.
i++;
In the update phase, we increment the counter. Since the counter is incremented before it is added to the sum, the loop adds the values 1 to 10. Forgetting to update the counter leads to an infinite loop.
$ java Main.java 55
The do while statement
The do while statement tests the condition after the body is
executed. Therefore, the body always runs at least once, even if the condition
is false from the start.
void main() {
int count = 0;
do {
System.out.println(count);
} while (count != 0);
}
The block is executed first, and then the condition is evaluated. In our case, the condition is false, so the loop terminates after a single iteration.
$ java Main.java 0
The for statement
When the number of iterations is known before the loop starts, the
for statement is usually the best choice. It puts the
initialization, the condition, and the update of a counter variable on one
line.
void main() {
for (int i = 0; i < 10; i++) {
System.out.print(i + " ");
}
System.out.println();
}
In this example, we print numbers 0 to 9 to the console.
for (int i = 0; i < 10; i++) {
System.out.print(i + " ");
}
There are three phases in a for loop. First, the counter i is
initialized to zero; this is done only once. Next comes the condition. If it is
true, the body is executed. Then the counter is incremented. Phases two and
three repeat until the condition is false. In our case, the loop ends when
i reaches 10. The i variable is only visible inside
the loop.
$ java Main.java 0 1 2 3 4 5 6 7 8 9
A for loop is commonly used to traverse an array. The length
field of the array gives its size.
void main() {
String[] planets = { "Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune" };
for (int i = 0; i < planets.length; i++) {
System.out.println(planets[i]);
}
System.out.println("In reverse:");
for (int i = planets.length - 1; i >= 0; i--) {
System.out.println(planets[i]);
}
}
We have an array holding the names of the planets of the Solar System. Using two for loops, we print them in ascending and descending order.
for (int i = 0; i < planets.length; i++) {
System.out.println(planets[i]);
}
Arrays use zero-based indexing; the first item has index 0. Therefore, the
i variable is initialized to zero. The condition checks that
i is less than the length of the array, and the update increments
it.
for (int i = planets.length - 1; i >= 0; i--) {
System.out.println(planets[i]);
}
This for loop prints the elements in reverse order. Since indexing is zero
based, the last element has the index planets.length - 1, which is
where the counter starts. The condition ensures that the counter is greater
than or equal to zero, because array indexes cannot be negative. In the update
phase, the counter is decremented.
$ java Main.java Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune In reverse: Neptune Uranus Saturn Jupiter Mars Earth Venus Mercury
The initialization and update parts of a for loop can contain several expressions separated by commas.
import java.util.Arrays;
import java.util.Random;
void main() {
var r = new Random();
int[] values = new int[10];
int num;
int sum = 0;
for (int i = 0; i < values.length; i++, sum += num) {
num = r.nextInt(10);
values[i] = num;
}
System.out.println(Arrays.toString(values));
System.out.println("The sum of the values is " + sum);
}
We fill an array with ten random numbers from 0 to 9 and calculate their sum.
for (int i = 0; i < values.length; i++, sum += num) {
num = r.nextInt(10);
values[i] = num;
}
The update part of the for loop has two expressions separated by a comma. The
i counter is incremented and the current number is added to the
sum variable. While this is legal, putting the summation into the
body is usually easier to read.
$ java Main.java [1, 2, 4, 7, 5, 4, 9, 7, 0, 2] The sum of the values is 41
Enhanced for statement
The enhanced for statement, also called the for-each loop,
simplifies traversing arrays and collections. It has no explicit counter. It
goes through the elements of an array or of any object that implements
Iterable one by one, and assigns the current element to the loop
variable.
void main() {
String[] planets = { "Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune" };
for (String planet : planets) {
System.out.println(planet);
}
}
We use the enhanced for statement to go through an array of
planets.
for (String planet : planets) {
System.out.println(planet);
}
The planets array is the source we iterate over, and
planet is the variable that holds the current element. Assigning a
new value to planet does not change the array. When we need the
index or want to modify the elements, we use the classic for loop.
$ java Main.java Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune
The break statement
The break statement terminates the innermost enclosing
while, do while, for, or
switch statement.
import java.util.Random;
void main() {
var random = new Random();
while (true) {
int num = random.nextInt(30);
System.out.print(num + " ");
if (num == 22) {
break;
}
}
System.out.println();
}
We define an endless while loop and use the break
statement to get out of it. In each iteration, we print a random value from 0
to 29. When the value equals 22, the loop ends.
while (true) {
...
}
Placing true in the round brackets of the while
statement creates an endless loop. The loop must be terminated from inside its
body, so we must make sure the exit condition is eventually reached.
if (num == 22) {
break;
}
When the randomly chosen value is equal to 22, the break
statement is executed and the while loop is terminated.
$ java Main.java 23 12 0 4 13 16 6 12 11 9 24 23 23 19 15 26 3 3 27 28 25 3 3 25 6 22 $ java Main.java 23 19 29 27 3 28 2 2 26 0 0 24 17 4 7 12 8 20 22 $ java Main.java 15 20 10 25 2 19 26 4 13 21 15 21 21 24 3 22
The continue statement
The continue statement skips the rest of the current iteration
and continues with the next one. It can be used in while,
do while, and for loops. In a for loop,
the update part is still executed before the next test.
In the following example, we print the odd numbers up to 20.
void main() {
int num = 0;
while (num < 20) {
num++;
if (num % 2 == 0) {
continue;
}
System.out.print(num + " ");
}
System.out.println();
}
We iterate through the numbers 1 to 20 with the while loop.
if (num % 2 == 0) {
continue;
}
If the expression num % 2 returns 0, the number is even. The
continue statement is executed and the rest of the iteration is
skipped, so the number is not printed. Note that the counter is incremented
at the top of the body; incrementing it after continue would
create an endless loop.
$ java Main.java 1 3 5 7 9 11 13 15 17 19
Labeled break and continue
In nested loops, a plain break or continue affects
only the innermost loop. To control an outer loop, we mark it with a label and
use the label in the statement.
void main() {
int[][] grid = {
{ 1, 4, 7 },
{ 2, 5, 8 },
{ 3, 6, 9 }
};
int target = 5;
outer:
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == target) {
System.out.printf("Found %d at [%d][%d]%n", target, row, col);
break outer;
}
}
}
}
We search a two-dimensional array for a value. Once the value is found, the
break outer statement terminates both loops, not just the inner
one. Similarly, continue outer would skip to the next iteration
of the outer loop.
$ java Main.java Found 5 at [1][1]
Source
Java Language Specification - Blocks, Statements, and Patterns
Java Control Flow statements - tutorial
In this article we have covered control flow in Java: the if,
else, and switch statements, switch expressions and
pattern matching, the while, do while,
for, and enhanced for loops, and the
break and continue statements.
Author
List all Java tutorials.