JDK 7 added support for String
with a switch
, which extended the list of types supported by switch
. As of Java 7, a switch
supported the primitive types byte
, short
, char
, and int
, their respective wrapper types (Byte
, Short
, Character
, and Integer
), enumerated types, and the String
type.
Does switch support objects other than Byte
, Short
, Character
, Integer
, enumerated types, and the String
type?
In Java 16, JEP 394 extended the instanceof
operator to take a type pattern and perform pattern matching. Leveraging this feature, in Java 21, JEP 441 made it possible to use case labels with patterns rather than just constants with switch
statements and expressions.
Demo:
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
class Main {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("[MMMM dd, uuuu][ h:mm a][ VV][ XXX]")
.localizedBy(Locale.ENGLISH);
static String format(Object obj) {
return switch (obj) {
case null -> "🤔";
case LocalDate date -> date.format(FORMATTER);
case LocalTime time -> time.format(FORMATTER).trim();
case OffsetDateTime odt -> odt.format(FORMATTER);
case ZonedDateTime zdt -> zdt.format(FORMATTER);
default -> obj.toString();
};
}
public static void main(String[] args) {
// Some sample values
ZoneId zone = ZoneId.of("America/New_York");
ZoneOffset offset = ZoneOffset.of("+05:30");
LocalDate date = LocalDate.of(2025, Month.FEBRUARY, 21);
LocalTime time = LocalTime.of(20, 30, 40);
OffsetDateTime odt = OffsetDateTime.of(date, time, offset);
ZonedDateTime zdt = ZonedDateTime.of(date, time, zone);
// Test format
System.out.println(format(date));
System.out.println(format(time));
System.out.println(format(odt));
System.out.println(format(zdt));
System.out.println(format(null));
System.out.println(format(Instant.now()));
}
}
Output from a sample run:
February 21, 2025
8:30 PM
February 21, 2025 8:30 PM +05:30
February 21, 2025 8:30 PM America/New_York -05:00
🤔
2025-02-22T11:25:36.329272700Z
case
dominanceIt also allows a guard clause with a case
in the form case <pattern> where <guard clause>
. The case
dominance rule must be maintained between cases with a guard clause. As per this rule, a more-dominant case
must be below a less-dominant case
. It is analogous to catch
blocks and the order of caught exceptions.
Demo:
class Main {
enum Day {MON, TUE, WED, THU, FRI, SAT, SUN}
public static void main(String[] args) {
Object[] values = {
-10, 20, false, Day.SAT, 30.0, Double.NaN, Day.THU, Day.SUN
};
for (Object obj : values) {
switch (obj) {
case Integer i when i > 0 ->
System.out.println("A positive integer");
case Integer i when i < 0 ->
System.out.println("A negative integer");
case Double d when d.isNaN() ->
System.out.println("0.0/0.0");
case Double d ->
System.out.println("Double - Not NaN");
case Day d when d == Day.SAT || d == Day.SUN ->
System.out.println("Weekend");
case Day d -> System.out.println("Weekday");
case null, default ->
System.out.println("Discard");
}
}
}
}
Output:
A negative integer
A positive integer
Discard
Weekend
Double - Not NaN
0.0/0.0
Weekday
Weekend
⚠️Warning: The order of case Double d when d.isNaN()
and case Double d
is important. It is because case Double d
dominates over case Double d when d.isNaN()
and therefore putting case Double d when d.isNaN()
below case Double d
will make case Double d when d.isNaN()
unreachable. Similar is the case with case Day d when d == Day.SAT || d == Day.SUN
and case Day d
.