百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

JDK21新特性:Pattern Matching for switch

yuyutoo 2025-06-23 23:14 3 浏览 0 评论

Pattern Matching for switch

JEP 441: Pattern Matching for switch

通过为 switch 表达式和语句添加模式匹配来增强 Java 编程语言。将模式匹配扩展到 switch 可以使表达式根据多个模式进行测试,每个模式都有特定的操作,从而能够简洁且安全地表达复杂的数据导向查询。

目标

■ 通过允许在 case 标签中使用模式,扩展 switch 表达式和语句的表现力和适用性。

■ 在需要时,允许放松 switch 对 null 的历史敌意(即允许更灵活地处理 null 值)。

■ 通过要求模式匹配的 switch 语句覆盖所有可能的输入值,提高 switch 语句的安全性。

■ 确保所有现有的 switch 表达式和语句无需修改即可继续编译,并以相同的语义执行。

现状

在 Java 16 中,JEP 394 扩展了 instanceof 操作符,使其可以接受类型模式并执行模式匹配。这一适度的扩展简化了常见的 instanceof-and-cast(即先检查类型再强制转换)惯用法,使其更加简洁且不易出错:

在新代码中,如果运行时 obj 的值是 String 类型的实例,那么 obj 就会匹配类型模式 String s。如果模式匹配成功,则 instanceof 表达式为 true,并且模式变量 s 会被初始化为 obj 强制转换为 String 后的值,然后可以在包含的代码块中使用。

经常需要将一个变量(例如 obj)与多个选项进行比较。Java 支持通过 switch 语句进行多路比较,并且自 Java 14 起支持 switch 表达式(JEP 361)。然而,不幸的是,switch 的功能非常有限。只能对少数类型的值进行 switch——包括整数基本类型(不包括 long)、它们对应的包装类、枚举类型和 String——而且只能测试是否与常量完全相等。

可能希望使用模式来测试同一个变量的多种可能性,并针对每种情况采取特定的操作。但由于现有的 switch 不支持这一点,最终我们不得不编写一连串的 if...else 测试,例如:

这段代码虽然受益于使用了模式匹配的 instanceof 表达式,但远非完美。首先,也是最重要的,这种方法允许编码错误隐藏起来,因为我们使用了一个过于通用的控制结构。在每个 if...else 分支中为 formatted 赋值,但没有任何机制可以让编译器识别并强制执行这一不变性。如果某个“then”块——也许是一个很少执行的分支——没有为 formatted 赋值,就会导致一个 bug。(将 formatted 声明为一个空白局部变量至少可以让编译器的确定性赋值分析发挥作用,但开发者并不总是这样写代码。)

此外,上述代码无法优化;即使底层问题通常是 O(1) 时间复杂度,但在没有编译器优化的情况下,它的时间复杂度仍然是 O(n)。

但是,switch 是模式匹配的完美选择!如果扩展 switch 语句和表达式以支持任何类型,并允许 case 标签使用模式而不是仅仅使用常量,那么可以更清晰、更可靠地重写上述代码:

这个 switch 的语义非常清晰:如果选择器表达式 obj 的值匹配 case 标签中的模式,则该 case 标签适用。(为了简洁起见,我们展示了 switch 表达式,但也可以展示 switch 语句;switch 块,包括 case 标签,都保持不变。)

这段代码的意图更加清晰,因为使用了正确的控制结构:“参数 obj 最多只匹配以下条件之一,找出匹配的条件并评估相应的分支。”作为额外的好处,它更容易优化;在这种情况下,更有可能以 O(1) 的时间复杂度完成分派。

switch 和 null

传统上,如果选择器表达式的值为 null,switch 语句和表达式会抛出 NullPointerException,因此对 null 的测试必须在 switch 外部完成:

当 switch 仅支持少数引用类型时,这种行为是合理的。然而,如果 switch 允许任何引用类型的表达式作为选择器,并且 case 标签可以包含类型模式,那么单独的 null 测试就显得像是一个不必要的区分,这不仅引入了冗余代码,还增加了出错的可能性。更好的方法是通过允许一个新的 case null 标签将 null 测试直接整合到 switch 中:

当选择器表达式的值为 null 时,switch 的行为始终由其 case 标签决定。如果存在 case null,则 switch 执行与该标签关联的代码;如果没有 case null,则 switch 会像以前一样抛出 NullPointerException。(为了向后兼容当前 switch 的语义,default 标签不会匹配 null 选择器。)

case 细化

与使用常量的 `case` 标签不同,模式 `case` 标签可以适用于多个值。这通常会导致在 `switch` 规则右侧出现条件代码。例如,考虑以下代码:

这里的问题是,使用单一模式来区分情况的方式无法扩展到多个条件。更希望编写多个模式,但需要某种方式来表达对模式的细化。因此,我们在 `switch` 块中允许使用 `when` 子句来为模式 `case` 标签指定保护条件(guard),例如:`case String s when s.equalsIgnoreCase("YES")`。将这种带有保护条件的 `case` 标签称为**带保护的 `case` 标签**,并将布尔表达式称为**保护条件**。

通过这种方式,可以使用保护条件重写上述代码:

这导致了一种更具可读性的 `switch` 编程风格,其中测试的复杂性出现在 `switch` 规则的左侧,而满足测试后执行的逻辑则在规则的右侧。

可以通过为其他已知的常量字符串添加额外规则来进一步增强此示例:

这些示例展示了常量 `case`、模式 `case` 和 `null` 标签如何结合在一起,展示 `switch` 编程的新能力:可以将以前混杂在业务逻辑中的复杂条件逻辑简化为一个可读的、顺序排列的 `switch` 标签列表,并将业务逻辑放在 `switch` 规则的右侧。

switch 和枚举常量

目前,枚举常量在 case 标签中的使用受到高度限制:switch 的选择器表达式必须是枚举类型,并且标签必须是枚举常量的简单名称。例如:

即使在添加模式标签后,这种限制仍然会导致代码过于冗长。例如:

如果可以为每个枚举常量单独设置一个 case,而不是使用大量带保护条件的模式,这段代码会更具可读性。因此,放宽了选择器表达式必须是枚举类型的限制,并允许 case 常量使用枚举常量的限定名称。这使得上述代码可以重写为:

现在,可以为每个枚举常量直接编写 case,而无需使用带保护条件的类型模式,后者之前只是用来绕过类型系统的现有限制。

小结

通过以下四种方式增强了 switch 语句和表达式:

  1. 改进枚举常量的 case 标签

支持使用枚举常量的限定名称(如 Suit.CLUBS),从而简化代码并提高可读性。

  1. 扩展 case 标签以支持模式和 null

除了常量外,case 标签现在还可以包含模式和 null,从而增强了表达能力。

  1. 扩大选择器表达式的类型范围

允许 switch 语句和表达式的选择器表达式使用更广泛的类型,同时引入了对 switch 块穷尽性分析的更丰富支持。

  1. 允许 case 标签后跟可选的 when 子句

引入了 when 保护条件,用于进一步细化模式匹配逻辑。

  1. 这些增强功能使 switch 更加灵活、简洁和安全,适用于更多场景,尤其是复杂的数据驱动查询和模式匹配需求。

引用:

https://openjdk.org/jeps/441

相关推荐

Java 代理模式详解(java代理类应用场景)

1.代理模式代理模式是一种比较好理解的设计模式。简单来说就是我们使用代理对象来代替对真实对象(realobject)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象...

深入解析Java工厂模式及其应用场景

Java工厂模式(FactoryPattern)是一种创建型设计模式,它提供了一种创建对象的最佳实践,这种模式提供了一种抽象工厂,通过使用工厂方法来创建对象。工厂方法将对象的创建推迟到子类中,这样就...

java之数据格式化(java中格式化快捷键)

数据格式化概述1、对属性对象的输入/输出进行格式化,从其本质上讲依然属于“类型转换”的范畴。...

Java之程序中的套路(设计模式的介绍)

前言本文主要是给大家简单地介绍一下设计模式的概念,文中会使用通俗易懂的案例,使你更好地学习本章知识点并理解原理,做到有道无术一.什么是设计模式首先我们得知道什么是设计模式。所谓的...

java文本对比工具源码5(java 文本对比)

/***Locatethebestinstanceof'pattern'in'text'near'...

Java微服务-设计模式系列全套文章-适配器模式(Adapter Pattern)

模式动机适配器模式(AdapterPattern)是一种使用频率非常高的结构型模式,如果在系统中存在不兼容的接口,可以通过引入一个适配器来使得原本因为接口不兼容而不能一起工作的两个类可以协同工作。适配...

Java 20 发布,新特性一览:Amber、Loom 和 Panama 项目

作者|MichaelRedlich译者|张卫滨...

Java语法入门004(java语法合集)

上篇是java语法入门003,继续学习Java[1]。...

Java8优雅编码实战:10个技巧让你的代码焕然一新

引言:为什么你的Java代码还不够优雅?“代码质量直接决定开发效率与系统稳定性。据Gartner统计,60%的线上故障源于低级编码错误。本文基于10万+行生产代码优化经验,提炼Java8的10大核心...

Java中常见的设计模式汇总?(java三种常用设计模式和实例)

设计模式是一套经过验证的设计方案和最佳实践,这些经验和方案主要就是用来解决软件设计过程中一些特定的问题。设计模式并不是代码本身,而是一种用来解决某种问题的抽象的解决方案,也就是说设计模式是在不同的语言...

Java字符串拼接3大隐藏陷阱!你的代码为何越优化越慢-附提速代码

导语:“某电商平台因一行字符串拼接代码,每秒多消耗1GB内存!本文通过性能压测对比+字节码反编译,揭秘看似简单的字符串操作如何拖垮你的系统。文末附性能检测工具+优化模板,点击关注领取实战方案!”...

JDK21新特性:Pattern Matching for switch

PatternMatchingforswitchJEP441:PatternMatchingforswitch...

java设计模式-行为型:观察者、责任链、备忘录、命令、状态

责任链模式(ChainofResponsibilityPattern)是行为型设计模式的一种。在责任链模式中,多个处理器都有机会处理请求,但是每个处理器都决定它是否可以处理该请求以及它是否应该将...

Java设计模式之外观模式(外观模式类图)

一、外观模式介绍1.1外观模式定义外观模式(FacadePattern),也叫门面模式,外观模式的原始定义是:为子系统中的一组接口提供统一的接口。它定义了一个更高级别的接口,使子系统更易于使用...

java文本对比工具源码1(java快速对比数据)

/**DiffMatchandPatch*Copyright2018Thediff-match-patchAuthors....

取消回复欢迎 发表评论: