In Java 17 (released only a few days ago), Pattern Matching for switch has been introduced as a preview language feature, which allows case labels with patterns rather than just constants. Here is an example showing how you can match on type patterns:
public static String typedPatternMatching(Object o) { return switch(o) { case null -> "I am null"; case String s -> "I am a String. My value is " + s; case Integer i -> "I am an int. My value is " + i; default -> "I am of an unknown type. My value is " + o.toString(); }; } // Output: > typedPatternMatching("HELLO") "I am a String. My value is HELLO" > typedPatternMatching(123) "I am an int. My value is 123" > typedPatternMatching(null) "I am null" > typedPatternMatching(0.5) "I am of an unknown type. My value is 0.5"
You can also use a guarded pattern in order to refine a pattern so that it is only matched on certain conditions, for example:
public static String guardedPattern(Collection<String> coll) { return switch(coll) { case List list && (list.size() > 10) -> "I am a big List. My size is " + list.size(); case List list -> "I am a small List. My size is " + list.size(); default -> "Unsupported collection: " + coll.getClass(); }; }
If you have a Sealed Class (made a permanent language feature in Java 17), the compiler can verify if the switch statement is complete so no default
label is needed. For example:
sealed interface Vehicle permits Car, Truck, Motorcycle {} final class Car implements Vehicle {} final class Truck implements Vehicle {} final class Motorcycle implements Vehicle {} public static String sealedClass(Vehicle v) { return switch(v) { case Car c -> "I am a car"; case Truck t -> "I am a truck"; case Motorcycle m -> "I am a motorcycle"; }; }