Appearance
Control Flow Statements in Java: Decision Making, Looping, and Branching
Every program you write needs to make decisions. Should this code run or not? Should you repeat this action ten times? Should you stop early if a condition is met? These are the kinds of questions that control flow statements answer. Without them, your program would just execute every line from top to bottom with no intelligence at all.
Control flow statements in Java fall into three broad categories:
- Decision making statements like
if,if else, andswitch - Iterative statements like
for,while, anddo whileloops - Branching statements like
breakandcontinue
By the end of this article you will understand all three categories deeply, know the rules that Java enforces around them, and be prepared for the interview questions that come up around these topics constantly.
Decision Making Statements
The if Statement
Think about your morning routine. If it is raining outside, you grab an umbrella. That is an if statement in real life. You check a condition, and if that condition is true, you do something.
In Java, the structure looks like this:
java
int value = 13;
if (value > 8) {
System.out.println("Value is greater than 8");
}The condition inside the parentheses must evaluate to a boolean, either true or false. If it is true, the block of code inside the curly braces executes. If it is false, the block is skipped entirely and Java moves on to whatever comes after it.
The if else Statement
Now imagine you want to do one thing when the condition is true and a completely different thing when it is false. That is where else comes in.
java
int marks = 45;
if (marks >= 50) {
System.out.println("You passed!");
} else {
System.out.println("You failed. Try again.");
}Only one of these two blocks will ever execute for any given value of marks. They are mutually exclusive.
The if else if Ladder
What if you have more than two possible outcomes? You chain conditions together using else if. Think about a grading system:
java
int marks = 72;
if (marks >= 90) {
System.out.println("Grade: A");
} else if (marks >= 80) {
System.out.println("Grade: B");
} else if (marks >= 70) {
System.out.println("Grade: C");
} else if (marks >= 60) {
System.out.println("Grade: D");
} else {
System.out.println("Grade: F");
}Java evaluates these conditions from top to bottom. The moment one condition is true, that block executes and all the remaining conditions are skipped. This is important: even if multiple conditions could theoretically be true, only the first matching one runs.
For marks = 72, the first condition (marks >= 90) is false, the second (marks >= 80) is false, and the third (marks >= 70) is true, so "Grade: C" prints and Java jumps past the rest.
Nested if Statements
You can place an if statement inside another if statement. This is called nesting. There is no limit to how deep you can nest, though deep nesting usually signals that your logic needs to be reorganized.
java
int value = 13;
if (value > 8) {
// We are now inside the outer if block
if (value < 15) {
System.out.println("Value is greater than 8 but less than 15");
} else {
System.out.println("Value is greater than or equal to 15");
}
}Here value = 13 is greater than 8, so we enter the outer block. Inside that block, 13 is less than 15, so we enter the inner if and print the message. The inner else is skipped.
The Switch Statement
The switch statement is an alternative to a long chain of if else if conditions. It works especially well when you are comparing one variable against many specific constant values.
Think of a TV remote. You press a button (channel 1, 2, 3, etc.) and a specific action happens based on which button you pressed. That is exactly what switch does.
Basic Switch Syntax
java
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
case 4:
System.out.println("Thursday");
break;
default:
System.out.println("Weekend or invalid day");
}Java takes the value of day (which is 3) and checks it against each case value from top to bottom. When it finds case 3, it executes that block and prints "Wednesday".
Using an Expression as the Switch Value
You are not limited to passing a simple variable. You can pass an expression:
java
int a = 1;
int b = 2;
switch (a + b) { // expression value is 3
case 1:
System.out.println("Sum is 1");
break;
case 2:
System.out.println("Sum is 2");
break;
case 3:
System.out.println("Sum is 3");
break;
default:
System.out.println("Other sum");
}Java evaluates a + b to get 3, then looks for case 3, finds it, and prints "Sum is 3".
Fall Through: One of the Most Important Switch Concepts
This is something that trips up beginners and comes up constantly in interviews. In Java, when a case matches and there is no break statement at the end of that case block, execution continues falling through into the next case block, and the next, and the next, until it either hits a break or reaches the end of the switch.
java
int value = 2;
switch (value) {
case 1:
System.out.println("Case 1");
case 2:
System.out.println("Case 2"); // matches here
case 3:
System.out.println("Case 3"); // falls through to here!
case 4:
System.out.println("Case 4"); // falls through to here!
break;
case 5:
System.out.println("Case 5");
}Output:
Case 2
Case 3
Case 4This surprises people. Java matched case 2, but because there was no break, it kept executing case 3 and case 4 as well. Case 4 has a break, so execution stops there. Case 5 never runs.
Fall through is not always a bug. Sometimes it is intentional and useful. For example, grouping months into quarters:
java
String month = "February";
switch (month) {
case "January":
case "February":
case "March":
System.out.println("Month is in Quarter 1");
break;
case "April":
case "May":
case "June":
System.out.println("Month is in Quarter 2");
break;
default:
System.out.println("Other quarter");
}Here January, February, and March all fall through to the same println statement. This is intentional grouping using fall through.
Switch Rules You Must Know
Java has strict rules about what you can and cannot use in a switch statement. These come up in every Java interview.
Allowed data types in the switch expression:
In the classic switch you can use exactly 10 types:
byteand its wrapperByteshortand its wrapperShortintand its wrapperIntegercharand its wrapperCharacterStringenum
Not allowed in switch expressions:
longfloatdoubleboolean
(Since Java 21, pattern matching lets a switch work on any object type; see the pattern matching for switch chapter.)
Additional switch rules:
- Two cases cannot have the same value. You cannot write
case 3twice in the same switch. The compiler will reject it. - Case values must be constants or literals, not variables. You can use a literal like
case 5, or a final variable likecase MY_CONSTANT, or an enum value, but you cannot use a regular variable likecase x. - The
defaultcase is optional but highly recommended. It handles anything that does not match any case, like theelseclause in anif else ifladder. - The
defaultcase does not have to be at the bottom. You can put it anywhere in the switch. Java will still evaluate it only when no other case matches.
java
final int MAX = 100;
switch (someValue) {
case 1: // literal, allowed
break;
case MAX: // final variable, allowed (it's a compile-time constant)
break;
// case x: // regular variable, NOT allowed
}Switch Expression (Java 14 and Later)
Java 12 previewed, and Java 14 made standard, a modernized switch that works as an expression rather than just a statement. The big difference is the arrow -> syntax, which eliminates fall through entirely and makes the code much cleaner.
Arrow Syntax
java
int day = 3;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid day";
};
System.out.println(dayName); // WednesdayNotice several things:
- The switch now returns a value, which you can assign to a variable.
- Each case uses
->instead of:. - There is no
breakanywhere. Fall through cannot happen with arrow syntax. - All possible cases must be handled. If you do not cover every possible value, you must include a
default.
Grouping Cases in Arrow Syntax
You can handle multiple values in one case using a comma separated list:
java
int month = 2;
String quarter = switch (month) {
case 1, 2, 3 -> "Quarter 1";
case 4, 5, 6 -> "Quarter 2";
case 7, 8, 9 -> "Quarter 3";
case 10, 11, 12 -> "Quarter 4";
default -> "Invalid month";
};
System.out.println(quarter); // Quarter 1This is cleaner than the fall through grouping of the traditional switch.
The yield Statement
An arrow case can hold a single expression, or a whole block in { }. When a block must produce the switch's value, you return it with yield.
yield is used inside a switch expression to return a value from a block:
java
int value = 3;
String result = switch (value) {
case 1 -> "One";
case 2 -> "Two";
case 3 -> {
// You can write multiple lines here
String msg = "The value is three";
System.out.println("Computing result...");
yield msg; // yield returns the value from this block
}
default -> "Other";
};
System.out.println(result);Think of yield as the return statement specifically for switch expressions. You use it when a case needs more than one line of logic before producing its value.
Iterative Statements (Loops)
Loops let you repeat a block of code multiple times without writing it out multiple times. Imagine printing numbers from 1 to 1000. You would not write System.out.println one thousand times. A loop does it in three lines.
The for Loop
The for loop is used when you know in advance how many times you want to iterate. It has three parts in its header: initialization, condition, and update.
java
for (int i = 1; i <= 5; i++) {
System.out.println("Count: " + i);
}Output:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5How it works step by step:
int i = 1runs once at the start (initialization).i <= 5is checked. If true, the body runs. If false, the loop ends.- After the body runs,
i++executes (update). - Go back to step 2 and repeat.
You can count backwards too:
java
for (int i = 10; i >= 1; i--) {
System.out.println(i);
}The while Loop
The while loop is used when you do not know in advance how many times you will iterate. The loop continues as long as the condition is true.
java
int value = 1;
while (value <= 5) {
System.out.println(value);
value++;
}Output:
1
2
3
4
5The variable is initialized before the loop. The condition is checked at the top. The update happens inside the body. The loop stops as soon as value becomes 6, because 6 <= 5 is false.
Important: With a while loop, if the condition is false from the very beginning, the loop body never executes at all. The body runs zero times.
The do while Loop
The do while loop is the one you use when you need the loop body to execute at least once, regardless of the condition.
java
int value = 10;
do {
System.out.println("This always runs at least once: " + value);
value++;
} while (value <= 5);Output:
This always runs at least once: 10Even though 10 <= 5 is false, the body still ran once because the condition is checked at the bottom, after the first execution. This is the key difference between do while and while.
A practical use case: a menu driven program. You always want to show the menu at least once, then keep showing it as long as the user does not choose to exit.
java
Scanner scanner = new Scanner(System.in);
int choice;
do {
System.out.println("1. Play");
System.out.println("2. Settings");
System.out.println("3. Exit");
System.out.print("Enter choice: ");
choice = scanner.nextInt();
} while (choice != 3);The for each Loop (Enhanced for Loop)
The for each loop is designed specifically for iterating over arrays and collections. It is cleaner and less error prone than a traditional for loop when you just want to go through every element.
java
int[] numbers = {10, 20, 30, 40, 50};
for (int num : numbers) {
System.out.println(num);
}Read this as: "for each num in numbers, print it."
You do not manage an index variable. You do not worry about going out of bounds. You just get each element in order.
java
String[] fruits = {"Apple", "Banana", "Cherry"};
for (String fruit : fruits) {
System.out.println(fruit);
}Output:
Apple
Banana
CherryThe for each loop also works with any class that implements the Iterable interface, which includes all Java collections like ArrayList, HashSet, LinkedList, and so on.
Branching Statements
break
The break statement immediately exits the nearest enclosing loop or switch statement. Execution continues with the first statement after the loop or switch.
java
for (int value = 1; value <= 10; value++) {
if (value == 5) {
break; // stop the loop when value reaches 5
}
System.out.println(value);
}Output:
1
2
3
4When value becomes 5, the break fires and the loop ends. 5 itself is never printed because the check happens before the print statement in this example. You can rearrange the order depending on your needs.
continue
The continue statement skips the rest of the current iteration and jumps to the next one. Unlike break, it does not exit the loop. The loop keeps going.
java
for (int value = 1; value <= 10; value++) {
if (value == 3) {
continue; // skip 3, go to next iteration
}
System.out.println(value);
}Output:
1
2
4
5
6
7
8
9
10Number 3 is skipped. Everything else prints normally. The loop runs all 10 iterations, but when value == 3 the continue causes the println to be skipped for that iteration only.
break and continue in Nested Loops
When you have loops inside loops, break and continue by default affect only the innermost loop they are inside.
java
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
break; // only breaks the inner loop
}
System.out.println("i=" + i + ", j=" + j);
}
}Output:
i=1, j=1
i=2, j=1
i=3, j=1The inner loop breaks when j == 2, but the outer loop keeps going through all three values of i. For each value of i, the inner loop runs, prints j=1, then breaks when j would become 2.
Similarly, continue in a nested loop only affects the innermost loop:
java
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
continue; // skips j=2 in the inner loop
}
System.out.println("i=" + i + ", j=" + j);
}
}Output:
i=1, j=1
i=1, j=3
i=2, j=1
i=2, j=3
i=3, j=1
i=3, j=3j=2 is skipped for every value of i.
Labeled break: Breaking Out of Multiple Loops
What if you want to break out of the outer loop from inside a nested loop? By default break only exits the innermost loop. To break out of an outer loop you use a labeled break.
A label is an identifier followed by a colon that you place before the loop you want to target.
java
outer: // this is the label for the outer loop
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == 2 && j == 2) {
break outer; // breaks out of the outer loop
}
System.out.println("i=" + i + ", j=" + j);
}
}
System.out.println("Exited both loops");Output:
i=1, j=1
i=1, j=2
i=1, j=3
i=2, j=1
Exited both loopsWhen i==2 and j==2, the break outer does not just exit the inner loop. It exits the loop labeled outer, which is the outer for loop. Execution jumps to the line after that outer loop.
You can also use labeled continue to skip an iteration of an outer loop:
java
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
continue outer; // skips to next iteration of outer loop
}
System.out.println("i=" + i + ", j=" + j);
}
}Output:
i=1, j=1
i=2, j=1
i=3, j=1When j == 2, instead of continuing the inner loop, continue outer skips to the next iteration of the outer loop. So j=2 and j=3 never print for any value of i.
Check yourself
- When does an
if else ifladder stop checking conditions? - What is fall through in a switch, and when is it useful?
- Which types can a classic switch use? Can two cases have the same value? Can a case use a normal variable?
- How does a switch expression differ from a switch statement? What does
yielddo? - What is the difference between
whileanddo while? - What is the difference between
breakandcontinue? What does a labeledbreakdo?
Answers
- At the first condition that is
true; the rest are skipped. - Without
break, execution continues into the following cases. It is useful for grouping several cases that share one action, such as months of a quarter. byte,short,int,char, their wrappers,String, and enums (notlong,float,double,boolean). No duplicate case values. Case labels must be constants (literals,finalconstants, or enum values).- A switch expression produces a value, uses
->with no fall through, and must cover every value (usually withdefault).yieldreturns the value from a block inside a case. whilechecks the condition first, so the body may run zero times;do whileruns the body once before checking.breakexits the loop (or switch);continueskips to the next iteration. A labeledbreakexits the outer loop named by the label.