Skip to main content
Advertisement

4.3 Switch Expressions and Pattern Matching (Java 14+)

Since Java 14, the switch statement has been significantly upgraded. Now switch can be used not just as a statement but as an expression that returns a value. Java 21 further enhanced it with pattern matching support.

1. Problems with the Old switch Statement

The old switch was prone to fall-through bugs when break was accidentally omitted.

// ❌ Old style - risk of fall-through bugs
int day = 2;
String dayName;

switch (day) {
case 1:
dayName = "Monday";
break; // Forgetting this causes fall-through to the next case!
case 2:
dayName = "Tuesday";
break;
case 3:
dayName = "Wednesday";
break;
default:
dayName = "Other";
}

2. Switch Expressions (Java 14+) - Arrow (->) Syntax

The new arrow syntax works without break and no fall-through occurs. Each case is independent and can directly return a value.

// ✅ New style - concise and safe!
int day = 2;
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); // Tuesday

Grouping Multiple case Values

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

System.out.println(type); // Weekend

3. The yield Keyword - Returning Values from Blocks

When multiple lines of code are needed after an arrow, use a { } block and return the value with yield.

int score = 85;
String grade = switch (score / 10) {
case 10, 9 -> "A";
case 8 -> {
System.out.println("Great job! Grade B.");
yield "B"; // Use yield to return from a block
}
case 7 -> "C";
case 6 -> "D";
default -> {
System.out.println("Keep trying!");
yield "F";
}
};

System.out.println("Grade: " + grade); // Grade: B

4. instanceof Pattern Matching (Java 16+)

Previously, you had to check instanceof and then cast separately. Now you can do both in one step.

// ❌ Old style (3 steps)
Object obj = "Hello, Java!";
if (obj instanceof String) { // 1. Type check
String s = (String) obj; // 2. Manual cast
System.out.println(s.length()); // 3. Use
}

// ✅ Pattern matching (Java 16+) - all in one!
if (obj instanceof String s) { // Check + cast + variable declaration!
System.out.println(s.length()); // Use s directly
}

Real-World Example: Shape Area Calculation

sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}

static double getArea(Shape shape) {
if (shape instanceof Circle c) {
return Math.PI * c.radius() * c.radius();
} else if (shape instanceof Rectangle r) {
return r.width() * r.height();
} else if (shape instanceof Triangle t) {
return 0.5 * t.base() * t.height();
}
throw new IllegalArgumentException("Unknown shape");
}

5. Switch Pattern Matching (Java 21)

Java 21 officially supports type pattern matching in switch expressions!

static String describe(Object obj) {
return switch (obj) {
case Integer i -> "Integer: " + i;
case Double d -> "Double: " + d;
case String s -> "String (length " + s.length() + "): " + s;
case null -> "null value";
default -> "Unknown type: " + obj.getClass().getName();
};
}

Guarded Patterns (Java 21)

Add additional conditions using the when clause.

static String classifyNumber(Object obj) {
return switch (obj) {
case Integer i when i < 0 -> "Negative: " + i;
case Integer i when i == 0 -> "Zero";
case Integer i when i > 0 -> "Positive: " + i;
default -> "Not an integer";
};
}

Pro Tip

Key things to note with switch expressions:

  • Switch expressions must handle all possible cases — you'll get a compile error without default.
  • You can switch on String, enum, integer types, wrapper types, and from Java 21, any Object.
  • enum + switch expression is the most common real-world pattern. Adding a new enum constant gives a compile error on unhandled cases.
enum Season { SPRING, SUMMER, AUTUMN, WINTER }

Season season = Season.SUMMER;
int avgTemp = switch (season) {
case SPRING -> 15;
case SUMMER -> 30;
case AUTUMN -> 18;
case WINTER -> -2;
// No default needed - all enum values are handled
};
Advertisement