与 if-else 一样,switch 语法是用来做条件判断的。当条件清晰简洁时,能够有效地提升代码可读性。switch 语法从 Java5 开始,Java12 增加了 Switch 表达式(Java14 提供正式版),Java17 增加 Switch 模式匹配(预览版)。
本文的目标是期望读者可以掌握 Switch 语法的所有能力,在需要的时候信手拈来。

if-else 与 switch 语法

我们先来个简单的例子看看 if-else 和 switch 语法的使用:
public static void demoOfIf(int num) {
if (num == 0) {
System.out.println(“0”);
} else if (num == 1) {
System.out.println(“1”);
} else if (num == 2) {
System.out.println(“2”);
} else {
System.out.println(“3”);
}
}

public static void demoOfSwitch(int num) {
switch (num) {
case 0: {
System.out.println(“0”);
break;
}
case 1: {
System.out.println(“1”);
break;
}
case 2: {
System.out.println(“2”);
break;
}
default: {
System.out.println(“3”);
}
}
}

上面的示例很简单,下面我们就来着重学习一下 Swith 语法。

Switch 块通用语法

switch(integral-selector) {
case value1: statement1; break;
case value2: statement2; break;
// ……
default: default-statement;
}

switch 语句是一种多路选择的简洁表达式,在 Java7 之前,switch 语句的表达式必须是整数值,这样会有很多的限制。于是在 Java7 中增加了 String 格式的支持,使应用场景更加丰富。
每个 case 执行语句末尾都有一个break关键字,它会让执行流程跳到 switch 的末尾。如果不加break,后面的 case 语句会继续执行,直到第一个break关键字。
比如:
public static void noBreak(int num) {
switch (num) {
case 0: {
System.out.println(“0”);
}
case 1: {
System.out.println(“1”);
}
case 2: {
System.out.println(“2”);
break;
}
default: {
System.out.println(“3”);
}
}
}

执行noBreak(0)的结果会是:
0
1
2
基于这种特性,我们可以合并多个值的执行逻辑,比如下面这种写法:
public static void noBreak2(int num) {
switch (num) {
case 0:
case 1:
case 2: {
System.out.println(“0 or 1 or 2”);
break;
}
default: {
System.out.println(“3”);
}
}
}

当参数是 0 或 1 或 2 时,结果相同,都是:
0 or 1 or 2

Switch 表达式

Switch 语句出现的姿势是条件判断、流程控制组件,与现在很流行的新语言对比,其写法显得非常笨拙,所以 Java 推出了 Switch 表达式语法,可以让我们写出更加简化的代码。这个扩展在 Java12 中作为预览版首次引入,需要在编译时增加-enable-preview开启,在 Java14 中正式提供,功能编号是 JEP 361。
比如,我们通过 switch 语法简单计算工作日、休息日,在 Java12 之前需要这样写:
@Test
void testSwitch() {
final DayOfWeek day = DayOfWeek.from(LocalDate.now());
String typeOfDay = “”;
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
typeOfDay = “Working Day”;
break;
case SATURDAY:
case SUNDAY:
typeOfDay = “Rest Day”;
break;
}

  1. Assertions.assertFalse(typeOfDay.isEmpty());<br />}

在 Java12 中的 Switch 表达式中,我们可以直接简化:
@Test
void testSwitchExpression() {
final DayOfWeek day = DayOfWeek.SATURDAY;
final String typeOfDay = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> “Working Day”;
case SATURDAY, SUNDAY -> “Day Off”;
};

  1. Assertions.assertEquals("Day Off", typeOfDay);<br />}

是不是很清爽。不过,这里有一点不足的是,如果是需要执行一段业务逻辑,然后返回一个结果呢?于是 Java13 使用yield关键字补齐了这个功能:
@Test
void testSwitchExpression13() {
final DayOfWeek day = DayOfWeek.SATURDAY;
final String typeOfDay = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
System.out.println(“Working Day: “ + day);
yield “Working Day”;
}
case SATURDAY, SUNDAY -> {
System.out.println(“Day Off: “ + day);
yield “Day Off”;
}
};

  1. Assertions.assertEquals("Day Off", typeOfDay);<br />}

Switch 模式匹配

到 Java17 时,又提供了 Switch 模式匹配功能。与 instanceof 模式匹配有些类似,是能够在 Switch 表达式实现类型自动转换。
比如:
static String formatterPatternSwitch(Object o) {
return switch (o) {
case null -> “null”;
case Integer i -> String.format(“int %d”, i);
case Long l -> String.format(“long %d”, l);
case Double d -> String.format(“double %f”, d);
case String s -> String.format(“String %s”, s);
default -> o.getClass().getSimpleName() + “ “ + o;
};
}

public static void main(String[] args) {
System.out.println(formatterPatternSwitch(null));
System.out.println(formatterPatternSwitch(“1”));
System.out.println(formatterPatternSwitch(2));
System.out.println(formatterPatternSwitch(3L));
System.out.println(formatterPatternSwitch(4.0));
System.out.println(formatterPatternSwitch(new AtomicLong(5)));
}

结果是:
null
String 1
int 2
long 3
double 4.000000
AtomicLong 5
可以看到,不只是类型自动转换,还可以直接判断是否是null,省了前置判断对象是否是null了。