Beginner Reading time: ~9 min

Control Structures

If-else, switch expressions, for, while, do-while loops, break, continue and labeled break

Control Structures

Control structures govern the execution flow of a program. Without them, every program would be a single sequential list of instructions.


1. Definition

What? Control structures are language constructs that determine the order in which statements are executed — conditionally, repeatedly, or by skipping certain blocks entirely.

Why? Every real-world program requires decisions and repetition. if, switch, for, while, and their companions are the building blocks of business logic, validation, data processing, and dynamic behavior.

Where?

  • Business rule evaluation (if/else, switch)
  • Collection and array traversal (for, for-each, while)
  • Input validation (do-while)
  • State machines and routing (switch expression)
  • Complex iteration control (break, continue, labeled break)

2. Core Concepts

2.1 Conditional Branching

Structure Description When to Use
if / else Basic conditional branch 1–3 branches, boolean condition
if / else if / else Multi-way conditional Multiple mutually exclusive conditions
switch (classic) Value-based branching One variable, several concrete values
switch expression (Java 14+) Value-returning switch Assigning to a variable, cleaner syntax
Ternary ? : Inline conditional Simple value assignment

2.2 Loops

Structure Description Typical Use
for Counter-based loop Known iteration count, index needed
for-each (for(T x : coll)) Iterator-based loop Full traversal of collection/array
while Pre-test loop Condition-dependent repetition
do-while Post-test loop At least one execution required

2.3 Control Transfer Statements

Keyword Effect
break Exits the current loop or switch
continue Skips the remainder of the current iteration
return Exits the method (optionally returning a value)
yield (Java 14+) Returns a value from a switch expression block
labeled break Exits a labeled outer loop
labeled continue Jumps to the next iteration of a labeled outer loop

2.4 Evolution of `switch`

Java 1.0  → classic switch (int, char)
Java 5    → enum support
Java 7    → String support
Java 14   → switch expression (preview → standard)
Java 17   → pattern matching in switch (preview)
Java 21   → pattern matching in switch (finalized)

3. Practical Application

Which Loop Should You Choose?

Situation Recommended Structure
Full array/list traversal, no index needed for-each
Index needed or step ≠ +1 for
Condition-dependent repetition, may run 0 times while
Must execute at least once (e.g., menu prompt) do-while
Infinite service loop while(true) + break

When `switch` vs `if-else`?

  • switch: single variable with multiple concrete values, enum routing, state machines
  • if-else: boolean expressions, range checks (x > 10), combining multiple variables
  • switch expression (Java 14+): when the branch produces a value
  • Pattern matching switch (Java 21+): type checking + casting in one construct

4. Code Examples

4.1 Classic Switch — ❌ Fall-through Bug

// ❌ BAD — missing break causes fall-through
switch (day) {
    case MONDAY:
        System.out.println("Monday");
        // missing break!
    case TUESDAY:
        System.out.println("Tuesday"); // also prints for MONDAY!
        break;
    default:
        System.out.println("Other day");
}
// ✅ GOOD — explicit break in every branch
switch (day) {
    case MONDAY:
        System.out.println("Monday");
        break;
    case TUESDAY:
        System.out.println("Tuesday");
        break;
    default:
        System.out.println("Other day");
}

4.2 Switch Expression (Java 14+)

// ✅ Modern switch expression — no fall-through, returns a value
String type = switch (statusCode) {
    case 200, 201 -> "Success";
    case 301, 302 -> "Redirect";
    case 404      -> "Not Found";
    case 500      -> "Server Error";
    default       -> "Unknown";
};

4.3 Switch Expression with `yield`

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    default -> {
        String s = day.toString();
        int result = s.length();
        yield result; // yield returns the block's value
    }
};

4.4 Pattern Matching in Switch (Java 21+)

// ✅ Type checking + casting combined in switch
static String format(Object obj) {
    return switch (obj) {
        case Integer i -> String.format("int: %d", i);
        case Long l    -> String.format("long: %d", l);
        case String s  -> String.format("String: %s", s);
        case null      -> "null";
        default        -> obj.toString();
    };
}

4.5 Guarded Pattern (Java 21+)

static String classify(Shape shape) {
    return switch (shape) {
        case Circle c when c.radius() > 100   -> "large circle";
        case Circle c                          -> "small circle";
        case Rectangle r when r.area() > 1000  -> "large rectangle";
        case Rectangle r                       -> "small rectangle";
        default                                -> "unknown";
    };
}

4.6 Labeled Break — Exiting Nested Loops

// ✅ Labeled break to exit the outer loop
outer:
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        if (matrix[i][j] == target) {
            System.out.println("Found at [" + i + "][" + j + "]");
            break outer; // exits the OUTER loop
        }
    }
}

4.7 Off-by-One Error

// ❌ BAD — ArrayIndexOutOfBoundsException
for (int i = 0; i <= arr.length; i++) { // should be < not <=
    System.out.println(arr[i]);
}

// ✅ GOOD
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}

4.8 Input Validation with `do-while`

// ✅ At least one execution guaranteed
int value;
do {
    System.out.print("Enter a positive number: ");
    value = scanner.nextInt();
} while (value <= 0);

4.9 `break` vs `continue`

// break — exits the loop entirely
for (int i = 0; i < 10; i++) {
    if (i == 5) break;       // loop ends, i = 5
    System.out.println(i);   // prints 0, 1, 2, 3, 4
}

// continue — skips to next iteration
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) continue; // skip even numbers
    System.out.println(i);    // prints 1, 3, 5, 7, 9
}

5. Trade-offs

Aspect Details
Readability for-each > for > while for collection traversal. switch expression > if-else chain when 4+ branches.
Performance The JIT compiler optimizes most loops to equivalent native code. for-each on an array compiles to the same bytecode as an indexed for.
switch vs if-else switch on integers and Strings generates tableswitch/lookupswitch bytecode — faster than an if-else chain for many branches.
Fall-through Classic switch fall-through can be useful for intentional grouping, but is error-prone. Switch expressions eliminate fall-through entirely.
Labeled break Powerful for nested loops, but overuse hurts readability — consider refactoring into a method instead.

6. Common Mistakes

| Mistake | Description | Prevention | | ---------------------------- | ----------------------------------------------------- | ------------------------------------------- | ------------------------------------------------- | ---------------------------------------------- | | Missing break | Fall-through in classic switch | Use switch expressions (Java 14+) | | Off-by-one | <= instead of < (or vice versa) in array indexing | Use for-each when index is not needed | | Infinite loop | Loop condition never becomes false | Always verify the loop variable is modified | | Boolean short-circuit | && and | | are short-circuit — side effects may be skipped | Avoid side-effecting expressions in conditions | | Unmodified loop variable | Forgetting to increment in while | Prefer for when a counter is needed | | Null in switch | NullPointerException before Java 21 | Use case null -> in Java 21+ |


7. Senior-Level Knowledge

7.1 Switch Expressions are Exhaustive

Since Java 14, switch expressions must be exhaustive — every possible value must be covered, or the code won't compile. For enums, this means handling all constants or providing a default branch.

7.2 Sealed Classes + Switch (Java 17/21)

sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double r) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double a, double b, double c) implements Shape {}

// Exhaustive — no default needed when all permitted classes are covered
double area(Shape shape) {
    return switch (shape) {
        case Circle c    -> Math.PI * c.r() * c.r();
        case Rectangle r -> r.w() * r.h();
        case Triangle t  -> {
            double s = (t.a() + t.b() + t.c()) / 2;
            yield Math.sqrt(s * (s - t.a()) * (s - t.b()) * (s - t.c()));
        }
    };
}

7.3 JIT Optimizations on Loops

  • Loop unrolling: the JIT unrolls small fixed-size loops
  • Loop vectorization: uses SIMD instructions where possible
  • Bounds check elimination: if the JIT can prove the index is always valid, it removes array bounds checks
  • Loop inversion: transforms while into do-while for better branch prediction

7.4 At the Bytecode Level

  • tableswitch: for contiguous value ranges (O(1) lookup)
  • lookupswitch: for sparse values (O(log n) binary search)
  • String switch: hashCode()-based lookupswitch + equals() verification

8. Glossary

Term Definition
Control structure A construct that directs the order of statement execution
Conditional branch if/else, ternary — choosing paths based on conditions
Loop Repeated execution of a block
Pre-test loop while — condition checked before each iteration
Post-test loop do-while — condition checked after each iteration
Labeled break Exiting an outer loop by label
Fall-through Execution falling into the next case in classic switch
Switch expression A value-returning switch (Java 14+)
Pattern matching Type-checking + destructuring in one step
Exhaustive Complete coverage — every case is handled
Guarded pattern A pattern with a when condition
Yield Keyword that returns a value from a switch expression block

9. Quick Reference

  • if/else — boolean conditions, 1–3 branches
  • switch (classic) — one variable's concrete values, watch out for break
  • switch expression (Java 14+) — -> syntax, no fall-through, returns a value
  • Pattern matching switch (Java 21+) — type checks, when guards, case null
  • for — known iteration count, index needed
  • for-each — collection/array traversal, no index
  • while — 0 or more repetitions, condition first
  • do-while — at least 1 execution, condition last
  • break — exit loop/switch
  • continue — skip to next iteration
  • return — exit method
  • yield — return a value from a switch expression block
  • Labeled break/continue — multi-level loop control
  • Sealed classes + switch — exhaustive pattern matching, no default needed
  • JIT: tableswitch = O(1), lookupswitch = O(log n)

🎼 Games

8 questions