案例

image-20250804151527738

  1. 假设上面表示形状的封闭类许可类是版本 1.0,它们被封装在一个基础 API 类库里 - 基础类库
  2. 而 isSquare 的实现代码,被封装在另一个 API 类库里 - 扩展类库

新加入一个许可类,用来表示长方形 - 基础类库的升级,扩展类库也要同步升级 - 但不一定能意识到

image-20250804153051943

  1. 对于需要更改扩展类库这件事,基础类库的作者,不会通知到扩展类库的作者
  2. 一般情况下,基础类库和扩展类库是独立的作品,由不同的团队和社区维护
    • 基础类库的作者不太可能意识到扩展类库的存在,更不可能去研究扩展类库的实现细节
    • 扩展类库维护者也不会注意到基础类库的修改,更不容易想到基础类库的修改会影响到扩展类库的行为

模式匹配的 switch

  1. 具有模式匹配能力的 switch - 将模式匹配扩展到 switch 语句switch 表达式
  2. 允许测试多个模式,每个模式多可以有特定的操作 - 简洁安全地表达复杂的面向数据的查询

image-20250804163730485

扩充的匹配类型

  1. 在 JDK 17 之前的 switch 关键字可以匹配的数据类型包括 - 数字枚举字符串 - 本质上都是整型原始类型
  2. 在 JDK 17 之后,匹配的目标数据类型,可以是一个引用类型
  3. 具有模式匹配能力的 switch,提升了 switch 的数据类型匹配能力
    • 整型的原始类型 - 数字、枚举、字符串
    • 引用类型

支持 null 情景模式

  1. 以前,switch 要匹配的数据不能是空引用 - 抛出 NullPointerException
  2. 规范的公开接口的代码,通常都要检查匹配数据是不是一个空引用,才能接着使用 switch 语句和 switch 表达式
1
2
3
4
5
6
7
8
9
10
public static boolean isSquare(Shape shape) {
if (shape == null) {
return false;
}

return switch (shape) {
case Shape.Circle c -> false;
case Shape.Square s -> true;
};
}
  1. 对于非公开接口的内部实现代码,不一定需要这样的非空检查
  2. 具有模式匹配能力的 switch,支持空引用的匹配 - 提高编码效率,降低代码错误

image-20250804170213147

可类型匹配的情景

  1. 既可以检查类型,还可以获得匹配变量
  2. 以前,switch 要匹配的数据是一个数值,对类型匹配来说,switch 要匹配的数据是一个引用
    • 此时,匹配场景要做的主要判断之一,希望知道这个引用类型

如果要匹配的数据是一个表示形状的类的引用
能够判断出来这个引用是一个圆形类的引用,还是正方形类的引用
如果情景能够匹配,希望能够获得匹配变量

1
case Shape.Circle c -> false;

穷举的匹配情景

  1. switch 表达式需要穷举出所有的情景,否则编译器会报错
  2. 如果代码编译期报错,那么扩展类库的维护者就能第一时间知道方法的缺陷
  3. 提前暴露问题的方式,大大降低了代码维护的难度
    • 意识到代码需要修改,往往是最难的一步

改进的性能

  1. 具有模式匹配能力的 switch 形式(包括 switch 语句switch 表达式),还提高了多情景处理性能
  2. 使用 if-else 的处理方式 - List - O(N)
    • 每一个情景,都至少对应一个 if-else 语句
    • 寻找匹配情景时,需要按照 if-else 的使用顺序来执行,直到遇到条件匹配的情景为止
    • 对于 if-else 语句来说,找到匹配情景的时间复杂度为 O(N)
  3. 使用 switch 处理方式 - Map - O(1)
    • 每一个情景,至少对应一个 case 语句
    • 寻找匹配情景时,switch 并不需要按照 case 语句的顺序执行
    • 对于 switch 的处理方式,找到匹配的情景的时间复杂度为 O(1)

default

只有待匹配类型的升级,不会影响 switch 表达式的逻辑,才会使用 default

  1. 使用了 default,意味着这样的 switch 表达式总能穷举出所有的情景
  2. 但这样会丧失检测匹配情景有没有变更的能力