Skip to content

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:

  1. Decision making statements like if, if else, and switch
  2. Iterative statements like for, while, and do while loops
  3. Branching statements like break and continue

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 4

This 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:

You can use exactly 10 types:

  • byte and its wrapper Byte
  • short and its wrapper Short
  • int and its wrapper Integer
  • char and its wrapper Character
  • String
  • enum

Not allowed in switch expressions:

  • long
  • float
  • double
  • boolean

The reason long, float, and double are excluded is that switch was designed for discrete exact matching, not ranges or approximations. The reason boolean is excluded is that you only have two possible values (true/false) and an if else is cleaner and more readable for that.

Additional switch rules:

  • Two cases cannot have the same value. You cannot write case 3 twice 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 like case MY_CONSTANT, or an enum value, but you cannot use a regular variable like case x.
  • The default case is optional but highly recommended. It handles anything that does not match any case, like the else clause in an if else if ladder.
  • The default case 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 12 and Later)

Java 12 introduced a modernized switch that works as an expression rather than just a statement. The big difference is the arrow -&gt; 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);  // Wednesday

Notice several things:

  • The switch now returns a value, which you can assign to a variable.
  • Each case uses -&gt; instead of :.
  • There is no break anywhere. 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 1

This is cleaner than the fall through grouping of the traditional switch.

The yield Statement

With arrow syntax you cannot write multiple lines of code in a case because the arrow expects a single expression. What if you need to do some computation before returning the value? That is where yield comes in.

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: 5

How it works step by step:

  1. int i = 1 runs once at the start (initialization).
  2. i &lt;= 5 is checked. If true, the body runs. If false, the loop ends.
  3. After the body runs, i++ executes (update).
  4. 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
5

The 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 &lt;= 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: 10

Even though 10 &lt;= 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
Cherry

The 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
4

When 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
10

Number 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=1

The 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=3

j=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 loops

When 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=1

When 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.


Interview Questions and Common Pitfalls

Q: What data types are allowed in a switch statement?

The allowed types are byte, short, int, char, their corresponding wrapper classes (Byte, Short, Integer, Character), String, and enum. That gives you 10 types in total.

Not allowed: long, float, double, boolean.

Q: Can two cases in a switch have the same value?

No. The compiler will reject this. Each case value must be unique within a switch statement.

Q: What is fall through in switch and is it a bug?

Fall through means that when a case matches and there is no break at the end, execution continues into the next case block. It is not always a bug. It can be used intentionally to group multiple cases that should produce the same result. However, unintentional fall through is a very common source of bugs.

Q: What is the difference between break and continue?

break exits the loop entirely. continue skips the rest of the current iteration and moves to the next one. The loop itself continues running with continue.

Q: What is the difference between while and do while?

A while loop checks its condition before executing the body. If the condition is false from the start, the body never runs. A do while loop executes the body first and checks the condition afterward. The body always runs at least once.

Q: When should you use switch instead of if else if?

Use switch when you are comparing a single variable or expression against a set of specific constant values. Switch is often cleaner and more readable in that scenario. Use if else if when you have range based conditions or conditions involving multiple variables.

Q: What is the yield statement in switch expressions?

yield is used inside a switch expression when a case block needs multiple lines of code before producing a value. It is like return but specifically for switch expressions. You cannot use return here because you might not be returning from the method, just providing a value for the switch expression.

Q: What is the difference between a switch statement and a switch expression?

A switch statement executes a block of code. A switch expression (introduced in Java 12) returns a value and can be assigned to a variable. Switch expressions use the -&gt; arrow syntax, eliminate fall through, and require exhaustive handling of all cases (all values must be covered or a default must be present).

Q: What does labeled break do?

Labeled break lets you break out of an outer loop from inside a nested loop. You put a label before the outer loop and reference that label in your break statement. Without a label, break only exits the innermost enclosing loop.

Q: Can the default case appear anywhere in a switch?

Yes. The default case does not have to be at the bottom. It can be placed anywhere in the switch block. Java will only execute it when no other case matches.


Putting It All Together

Here is a program that uses several of these concepts together:

java
public class ControlFlowDemo {
    public static void main(String[] args) {

        // if-else-if ladder
        int score = 78;
        if (score >= 90) {
            System.out.println("Excellent");
        } else if (score >= 75) {
            System.out.println("Good");  // this prints
        } else if (score >= 50) {
            System.out.println("Average");
        } else {
            System.out.println("Below average");
        }

        // switch expression (Java 12+)
        int month = 4;
        String season = switch (month) {
            case 12, 1, 2 -> "Winter";
            case 3, 4, 5 -> "Spring";   // matches here
            case 6, 7, 8 -> "Summer";
            case 9, 10, 11 -> "Autumn";
            default -> "Unknown";
        };
        System.out.println("Season: " + season);  // Season: Spring

        // for loop with break
        System.out.println("Searching for 7:");
        for (int i = 1; i <= 10; i++) {
            if (i == 7) {
                System.out.println("Found 7!");
                break;
            }
        }

        // for-each with continue (skip even numbers)
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8};
        System.out.println("Odd numbers:");
        for (int n : nums) {
            if (n % 2 == 0) {
                continue;  // skip even numbers
            }
            System.out.print(n + " ");
        }
        System.out.println();

        // labeled break to exit nested loops
        System.out.println("Labeled break demo:");
        outer:
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking at i=" + i + ", j=" + j);
                    break outer;
                }
            }
        }
    }
}

Summary

Control flow is the backbone of any non trivial program. Here is a quick recap of everything covered:

ConceptKey Point
if / else if / elseEvaluate conditions top to bottom, first match wins
Nested ifPlace if inside if, no depth limit but keep it readable
switch statementCompare one value against constants, uses fall through by default
Fall throughWithout break, execution flows into next case, intentional or not
Switch allowed typesbyte, short, int, char, their wrappers, String, enum. Not long, float, double, boolean
Switch expression (Java 12)Arrow syntax, no fall through, returns a value, exhaustive by requirement
yieldReturns a value from a multi line case block in a switch expression
for loopUse when iteration count is known in advance
while loopUse when iteration count is not known, condition checked first
do while loopBody always runs at least once, condition checked after
for each loopClean iteration over arrays and collections without index management
breakExits the innermost loop or switch entirely
continueSkips the current iteration, loop continues
Labeled breakExits a specific outer loop by name
Labeled continueSkips to next iteration of a specific outer loop

Master these building blocks and you will be able to express any logic your programs need. They form the foundation that everything else in Java is built upon.