概述

  1. Switch 表达式JDK 14 正式发布
  2. 在 Java 规范中,表达式完成对数据的操作
    • 表达式的结果:可以是一个数值(i * 4),也可以是一个变量(i = 4),或者什么都不是(void 类型)
  3. Java 语句是 Java 最基本的可执行单位,本身不是一个数值,也不是一个变量
    • Java 语句的标志符号为分号(代码)双引号(代码块)

Switch 语句

image-20241209182542013

break 语句

  1. 常见错误 - break 语句遗漏或者冗余
  2. 凡是使用 switch 语句的代码,都有可能成为黑客们重点关注的对象
    • 在 Code Review 时需重点关注 - 增加代码维护成本 + 降低生产效率
  3. break 语句是一个弊大于利的设计
    • 设计一门现代的语言,需要更多地使用 Switch 语句,但不要再使用 break 语句 - Go
  4. 需要依然存在 - 不同的场景共享代码片段

反复出现的赋值语句

  1. 本地变量声明实际赋值分开
  2. 在 Switch 语句中,本地变量没有被赋值,编译器也不会报错,使用缺省或者初始化的变量值
  3. 为了判断本地变量有没有合适的值,需要通览整个 Switch 语句块,确保赋值没有遗漏 - 维护成本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package ai.zhongmingmao.feature;

import java.util.Calendar;

class DaysInMonth {
public static void main(String[] args) {
Calendar today = Calendar.getInstance();
int month = today.get(Calendar.MONTH);
int year = today.get(Calendar.YEAR);

int daysInMonth = 0;
switch (month) {
case Calendar.JANUARY:
case Calendar.MARCH:
case Calendar.MAY:
case Calendar.JULY:
case Calendar.AUGUST:
case Calendar.OCTOBER:
case Calendar.DECEMBER:
daysInMonth = 31;
break;
case Calendar.APRIL:
case Calendar.JUNE:
case Calendar.SEPTEMBER:
case Calendar.NOVEMBER:
// daysInMonth = 30;
break; // WRONG, INITIAL daysInMonth value IS USED!!!
case Calendar.FEBRUARY:
if (((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0)) {
daysInMonth = 29;
} else {
daysInMonth = 28;
}
break;
default:
throw new RuntimeException("Calendar in JDK does not work");
}

System.out.printf("There are %d days in this month.%n", daysInMonth);
}
}

Switch 表达式

image-20241209184311504

  1. Switch 代码块出现在赋值运算符右侧
    • Switch 代码块表示的是一个数值,或者一个变量
    • Switch 代码块是一个表达式
  2. 多场景合并 - 一个 Case 语句可以处理多个情景 - 使用逗号分隔,共享代码块
    • 传统的 Switch 语句一个 Case 语句只能处理一个情景
    • break 语句Switch 表达式消失
  3. 可以在 Switch 表达式里使用冒号标识符,但一个 Case 语句只能匹配一个情景
  4. 箭头标识符右侧可以是表达式代码块或者异常抛出语句,不能是其它形式
  5. yield
    • 如果需要一个或多个语句时,需要使用代码块的形式,yield 语句产生一个值
    • yield 语句产生的值可以看成是 Switch 表达式返回值
    • yield 只能用于 Switch 表达式,而不能用于 Switch 语句
  6. 在 Switch 表达式中,需要穷举所有情景 - 使得代码更健壮,大幅降低维护成本

改进的 Switch 语句

Switch 语句可以使用箭头标识符,也可以使用 break 语句,也不需要列出所有的情景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static int daysInMonth(int year, int month) {
int daysInMonth = 0;
switch (month) {
case Calendar.JANUARY,
Calendar.MARCH,
Calendar.MAY,
Calendar.JULY,
Calendar.AUGUST,
Calendar.OCTOBER,
Calendar.DECEMBER ->
daysInMonth = 31;
case Calendar.APRIL, Calendar.JUNE, Calendar.SEPTEMBER, Calendar.NOVEMBER -> daysInMonth = 30;
case Calendar.FEBRUARY -> {
if (((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0)) {
daysInMonth = 29;
break;
}

daysInMonth = 28;
}
// default -> throw new RuntimeException("Calendar in JDK does not work");
}

return daysInMonth;
}

Switch 语句的改进主要体现在 break 语句的使用上

  1. break 语句没有出现在下一个 case 语句之前
  2. 使用箭头标识符Switch 语句不再需要 break 语句来实现情景间的代码共享
  3. 有没有 break 语句,使用箭头标识符的 Switch 语句都不会顺序执行下面的操作 - fall-through
  4. 使用箭头标识符的 Switch 语句并没有禁止 break 语句

怪味的 Switch 表达式

不再推荐使用冒号标识符Switch 语句Switch 表达式

  1. Switch 表达式也可以使用冒号标识符
  2. 使用冒号标识符一个 case 语句只能匹配一个场景,而且支持 fall-through
  3. 使用冒号标识符Switch 表达式不支持 break 语句,应该是使用 yield 语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package ai.zhongmingmao.feature;

import java.util.Calendar;

class DaysInMonth {
public static void main(String[] args) {
Calendar today = Calendar.getInstance();
int month = today.get(Calendar.MONTH);
int year = today.get(Calendar.YEAR);

int daysInMonth =
switch (month) {
case Calendar.JANUARY:
case Calendar.MARCH:
case Calendar.MAY:
case Calendar.JULY:
case Calendar.AUGUST:
case Calendar.OCTOBER:
case Calendar.DECEMBER:
yield 31;
case Calendar.APRIL:
case Calendar.JUNE:
case Calendar.SEPTEMBER:
case Calendar.NOVEMBER:
yield 30;
case Calendar.FEBRUARY:
if (((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0)) {
yield 29;
} else {
yield 28;
}
default:
throw new RuntimeException("Calendar in JDK does not work");
};

System.out.println("There are " + daysInMonth + " days in this month.");
}
}

小结

Switch 表达式 - yield 语句 + 穷举所有场景
箭头标识符 -> 不支持 fall-through + 多场景

  1. break 语句只能出现在 Switch 语句里,不能出现在 Switch 表达式里
  2. yield 语句只能出现在 Switch 表达式里,不能出现在 Switch 语句里
  3. Switch 表达式需要穷举所有场景,而 Switch 语句不需要
  4. 使用冒号标识符的 Switch 形式,支持 fall-through,而使用箭头标识符,则不支持 - Go
  5. 使用箭头标识符的 Switch 形式,一个 Case 语句支持多个场景,而冒号标识符不支持

优先选择 - 箭头标识符 + Switch 表达式