Control Flow in Java: if, else and switch

Decision making in Java, from the plain if statement to modern switch expressions and pattern matching.

The if statement

int marks = 72;

if (marks >= 75) {
    System.out.println("Distinction");
} else if (marks >= 50) {
    System.out.println("Pass");
} else {
    System.out.println("Fail");
}

The condition must be a boolean. Java does not treat zero or null as false, which removes a whole family of bugs found in other languages.

Important rules

  • An else binds to the nearest unmatched if. Braces make that explicit.
  • Only the first matching branch of an if / else if chain runs.
  • Assignment inside a condition is legal for boolean variables, which is exactly why = in place of == can slip through.

The conditional operator

String status = marks >= 50 ? "Pass" : "Fail";

Use it when both branches produce a value for the same variable. Nesting it more than once makes code that is technically correct and practically unreadable.

The classic switch statement

int day = 3;

switch (day) {
    case 1:
    case 7:
        System.out.println("Weekend");
        break;
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
        System.out.println("Weekday");
        break;
    default:
        System.out.println("Invalid day");
}

Execution jumps to the matching label and then falls through every following label until a break or the end of the block. The grouped labels above use that deliberately; a forgotten break uses it accidentally.

Switch expressions

Java 14 finalised a form that produces a value, uses arrow labels and does not fall through.

String type = switch (day) {
    case 1, 7 -> "Weekend";
    case 2, 3, 4, 5, 6 -> "Weekday";
    default -> "Invalid day";
};

When a branch needs several statements, wrap it in a block and produce the result with yield:

int fee = switch (category) {
    case "student" -> 100;
    case "member" -> {
        int base = 500;
        yield base - discount;
    }
    default -> 800;
};
A switch expression must be exhaustive. Over an enum that means covering every constant or supplying a default, and the compiler enforces it. This is a genuine advantage over the statement form.

What switch accepts

TypeAllowed
byte short char int and their wrappersYes
StringYes, since Java 7
enumYes
Any reference type, using patternsYes, since Java 21
long, float, double, booleanNo

Pattern matching for switch

Java 21 allows the selector to be matched against type patterns, which replaces long chains of instanceof tests.

static String describe(Object value) {
    return switch (value) {
        case null                 -> "nothing";
        case Integer i when i < 0 -> "negative number " + i;
        case Integer i            -> "number " + i;
        case String s             -> "text of length " + s.length();
        default                   -> "something else";
    };
}

The when clause adds a guard, and a matched variable such as i is already the right type inside its branch. Note that case null must be written explicitly; without it a null selector throws NullPointerException.

Common mistakes

  • Omitting break in a classic switch and processing more branches than intended.
  • Switching on a String that may be null without handling it.
  • Comparing strings in if with == rather than equals.
  • Deeply nested if blocks where an early return would read far better.

Best practices

  • Always use braces, even for a single statement.
  • Prefer the arrow form of switch in new code; fall through is a source of bugs, not a feature.
  • Return early to keep the main path of a method flat.
  • Order conditions so the common or cheap case is tested first.

Practice

  1. Convert the classic day switch above into a switch expression and explain what break was doing.
  2. Predict the output when the break statements are removed and day is 3.
  3. Write a method that returns a shipping charge for an enum Zone with values LOCAL, NATIONAL and INTERNATIONAL, with no default branch. Why does that compile?
  4. Rewrite a three level nested if of your own using early returns.

Conclusion

Branch on booleans, prefer the expression form of switch, and let the compiler check exhaustiveness for you. Modern control flow in Java is designed to make a missing case a compile error rather than a defect.

Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Java notes →
Java

Introduction to Java

Java is a statically typed, object oriented language that compiles to bytecode and runs on a virtual machine, which is what makes it portable.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.