New Java Feature - Switch Matching
案例
- 假设上面表示形状的封闭类和许可类是版本 1.0,它们被封装在一个基础 API 类库里 - 基础类库
- 而 isSquare 的实现代码,被封装在另一个 API 类库里 - 扩展类库
新加入一个许可类,用来表示长方形 - 基础类库的升级,扩展类库也要同步升级 - 但不一定能意识到
- 对于需要更改扩展类库这件事,基础类库的作者,不会通知到扩展类库的作者
- 一般情况下,基础类库和扩展类库是独立的作品,由不同的团队和社区维护
- 基础类库的作者不太可能意识到扩展类库的存在,更不可能去研究扩展类库的实现细节
- 扩展类库维护者也不会注意到基础类库的修改,更不容易想到基础类库的修改会影响到扩展类库的行为
模式匹配的 switch
- 具有模式匹配能力的 switch - 将模式匹配扩展到 switch 语句和 switch 表达式
- 允许测试多个模式,每个模式多可以有特定的操作 - 简洁安全地表达复杂的面向数据的查询
扩充的匹配类型
- 在 JDK 17 之前的 switch 关键字可以匹配的数据类型包括 - 数字、枚举和字符串 - 本质上都是整型的原始类型
- 在 JDK 17 之后,匹配的目标数据类型,可以是一个引用类型
- 具有模式匹配能力的 switch,提升了 switch 的数据类型匹配能力
- 整型的原始类型 - 数字、枚举、字符串
- 引用类型
支持 null 情景模式
- 以前,switch 要匹配的数据不能是空引用 - 抛出 NullPointerException
- 规范的公开接口的代码,通常都要检查匹配数据是不是一个空引用,才能接着使用 switch 语句和 switch 表达式
1 | public static boolean isSquare(Shape shape) { |
- 对于非公开接口的内部实现代码,不一定需要这样的非空检查
- 具有模式匹配能力的 switch,支持空引用的匹配 - 提高编码效率,降低代码错误
可类型匹配的情景
- 既可以检查类型,还可以获得匹配变量
- 以前,switch 要匹配的数据是一个数值,对类型匹配来说,switch 要匹配的数据是一个引用
- 此时,匹配场景要做的主要判断之一,希望知道这个引用类型
如果要匹配的数据是一个表示形状的类的引用
能够判断出来这个引用是一个圆形类的引用,还是正方形类的引用
如果情景能够匹配,希望能够获得匹配变量
1 | case Shape.Circle c -> false; |
穷举的匹配情景
- switch 表达式需要穷举出所有的情景,否则编译器会报错
- 如果代码编译期报错,那么扩展类库的维护者就能第一时间知道方法的缺陷
- 提前暴露问题的方式,大大降低了代码维护的难度
- 意识到代码需要修改,往往是最难的一步
改进的性能
- 具有模式匹配能力的 switch 形式(包括 switch 语句和 switch 表达式),还提高了多情景处理性能
- 使用 if-else 的处理方式 - List - O(N)
- 每一个情景,都至少对应一个 if-else 语句
- 寻找匹配情景时,需要按照 if-else 的使用顺序来执行,直到遇到条件匹配的情景为止
- 对于 if-else 语句来说,找到匹配情景的时间复杂度为 O(N)
- 使用 switch 处理方式 - Map - O(1)
- 每一个情景,至少对应一个 case 语句
- 但寻找匹配情景时,switch 并不需要按照 case 语句的顺序执行
- 对于 switch 的处理方式,找到匹配的情景的时间复杂度为 O(1)
default
只有待匹配类型的升级,不会影响 switch 表达式的逻辑,才会使用 default
- 使用了 default,意味着这样的 switch 表达式总能穷举出所有的情景
- 但这样会丧失检测匹配情景有没有变更的能力
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.