The switch Statement and switch Expression in Java

The switch in Java dispatches on a value. It used to be a clunky statement with fall-through bugs; modern Java turned it into a safer, more expressive construct that also works as an expression.

The classic switch statement

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;
    default:
        System.out.println("Unknown");
}

The break is critical. Without it, execution falls through to the next case β€” the classic bug source:

switch (day) {
    case 1:
        System.out.println("Monday");
        // forgot break
    case 2:
        System.out.println("Tuesday"); // also prints when day == 1!
        break;
}

Intentional fall-through

Sometimes fall-through is what you want β€” group several cases that share an action:

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

Switch expression (Java 14+)

The modern switch is an expression β€” it returns a value. No fall-through, no break, no surprises.

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

Arrow syntax (->) takes a single expression or a block. With a block, use yield to return a value:

int monthDays = switch (month) {
    case 4, 6, 9, 11 -> 30;
    case 2 -> {
        boolean leap = isLeapYear(year);
        yield leap ? 29 : 28;
    }
    default -> 31;
};

Switch on String

String command = "help";
switch (command) {
    case "start"   -> start();
    case "stop"    -> stop();
    case "help", "?" -> showHelp();
    default        -> System.out.println("Unknown command");
}

Case-sensitive. Internally uses hashCode + equals, so it's O(1) β€” faster than a chain of ifs.

Switch on enum

With enums, you don't qualify the constants:

enum Status { ACTIVE, IDLE, STOPPED }

Status s = Status.ACTIVE;
String msg = switch (s) {
    case ACTIVE  -> "Running";
    case IDLE    -> "Waiting";
    case STOPPED -> "Offline";
};

Beauty of the switch expression on an enum: if you later add a FAILED constant, the compiler forces you to handle it. No default needed β€” exhaustiveness is checked.

Pattern matching (Java 21+)

Java 21 made switch even more powerful with pattern matching:

Object obj = 42;

String description = switch (obj) {
    case Integer i when i > 0 -> "Positive int: " + i;
    case Integer i            -> "Non-positive int: " + i;
    case String s             -> "String of length " + s.length();
    case null                 -> "null";
    default                   -> "Something else";
};

The when clause adds a guard; null is now a real case. This replaces long chains of instanceof + cast.

Switch with sealed types

Combined with sealed interfaces, you get exhaustive case analysis:

sealed interface Shape permits Circle, Square, Triangle {}
record Circle(double r) implements Shape {}
record Square(double side) implements Shape {}
record Triangle(double base, double height) implements Shape {}

double area = switch (shape) {
    case Circle c   -> Math.PI * c.r() * c.r();
    case Square sq  -> sq.side() * sq.side();
    case Triangle t -> 0.5 * t.base() * t.height();
};
// No default needed β€” compiler knows all subclasses

Switch vs if-else

Use switch when...Use if-else when...
Comparing one value against many constantsConditions involve different variables
Enum or small set of valuesRange checks (x > 10, s != null)
Need compiler exhaustiveness check2-3 simple conditions
Pattern matching on typeComplex boolean logic

Common mistakes

  • Missing break in a statement-style switch.
  • Mixing arrow and colon syntax in the same switch β€” not allowed.
  • Empty default β€” remove it unless it really does nothing on purpose.
  • Expecting switch on Object before Java 21 β€” it only supports primitives, wrappers, String, enum, and (since 21) any type via pattern matching.

Modern recommendation

For new code on Java 14+, prefer the switch expression with arrow syntax. It's safer, shorter, and the compiler enforces exhaustiveness. Reach for if-else only when conditions involve different expressions or ranges.

Switch has gone from Java's dustiest feature to one of its most expressive constructs β€” take advantage of the modern form.