目录
1、JEP 427: Switch 的模式匹配(第三次预览)
概述
JDK 19 于 2022 年 9 月 20 日正式发布。
JEP(Java Enhancement Proposal)Java增强提案
CSR(Compatibility & Specification Review) 兼容性和规范审查
变动说明
官网:
Java Platform, Standard Edition Java Language Updates, Release 19
JDK 19 Release Notes, Important Changes, and Information
https://blogs.oracle.com/java/post/the-arrival-of-java-19
更多参考:
JDK 19 Documentation - Home 更多版本:Java Platform, Standard Edition Documentation - Releases
Java Platform, Standard Edition Oracle JDK Migration Guide, Release 19
重要变更和信息
JDK 19 包含 7 个 新特性 ,分别为:
-
JEP 405: Record Patterns (Preview) Record模式(预览特性)
-
JEP 422: Linux/RISC-V Port Linux/RISC-V移植
-
JEP 424: Foreign Function & Memory API (Preview) 外部函数和内存API(预览)
-
JEP 425: Virtual Threads (Preview) 虚拟线程(预览)
-
JEP 426: Vector API (Fourth Incubator) 向量API(第四次孵化)
-
JEP 427: Pattern Matching for switch (Third Preview) Switch的模式匹配(第三次预览)
-
JEP 428: Structured Concurrency (Incubator) 结构化并发(孵化特性)
而其中与开发过程中直接相关的特性主要包括:JEP 405(Record模式)、JEP 427(Switch 表达式的模式匹配)等。
下载地址
你可以从这个链接下载Oracle JDK
版本,更多版本下载。
也可以从这个链接下载生产就绪的OpenJDK
版本。文件为压缩包,解压并设置环境变量就可以使用。
Java19新特性总结
1、JEP 427: Switch 的模式匹配(第三次预览)
JEP 427 (specification/language
)
这仍然是一个预览特性
功能进化
switch
表达式的功能进化
java版本 | 特性类型 | JEP | 特性 |
---|---|---|---|
Java 5 | 首次引入,仅支持整型数据类型(如 byte , short , char , 和 int )及枚举类型 | ||
Java 7 | 支持 String 类型 | ||
Java 12 | 预览特性 | JEP 325 | 支持Switch 表达式(箭头函数) |
Java 13 | 预览特性 | JEP 354 | 加入 yield 语句来替代 break 语句,用于从 switch 表达式返回值 |
Java 14 | 正式特性 | JEP 361 | 前2个版本的新特性转为正式特性 |
Java 17 | 预览特性 | JEP 406 | 引入模式匹配的Switch 表达式作为预览特性 |
Java 18 | 第二次预览 | JEP 420 | 调整优化 |
Java 19 | 第三次预览 | JEP 427 | 调整优化 |
在 Java 16 中, JEP 394
将 instanceof
的模式匹配发布为正式属性。虽然可以不需要强制转换了,但是仍然需要大量的 if...else
。而 Switch 表达式虽然简化了if...else
,但是它无法像instanceof
一样不需要强制转换。为了解决这个痛点,Java 17
引入模式匹配的Switch
表达式特性 ,目前该特性为预览特性。
该特性扩展了 switch 表达式和语句,允许它们使用模式匹配,这就意味着我们可以在 switch
的 case 标签中使用模式,如类型模式,使得代码更加灵活和表达性更强。而且也无需进行显式的类型转换了。例如,可以使用 case Integer i
这样的语法来匹配并自动转换类型。
但是,不知道小伙伴们注意没有,Switch
表达式只有一种类型,比如:我有一个诗人类(Poet
),它有3个实现类:唐朝诗人(TangPoet
)、宋朝诗人(SongPoet
)、汉朝诗人(HanPoet
),我要根据诗人的类型进行不同处理 :
Poet poet = ... // 诗人 switch (poet.getClass().getName()) { case "my.poet.TangPoet": TangPoet tp = (TangPoet) obj; // 处理唐朝诗人 break; case "my.poet.SongPoet": SongPoet sp = (SongPoet) obj; // 处理宋朝诗人 break; case "my.poet.HanPoet": HanPoet hp = (HanPoet) obj; // 处理汉朝诗人 break; // 其他类型 }
这个强转显然比较麻烦。所以,参考Java 17
中,参考instanceof
的模式匹配,为switch
表达式引入了模式匹配功能作为预览特性。
Switch 模式匹配
在 Java 17 中,switch
表达式允许使用模式匹配来处理对象类型,这样就可以直接在 switch
语句中检查和转换类型,而不需要额外的 if...else
结构和显式类型转换。
case
后面可以跟的标签主要有:
-
类型标签
-
null标签
-
守卫标签
-
enum或常量值
类型标签
允许在 switch
语句的 case 分支中直接匹配对象的类型。例如,case String s
允许你在该分支中直接作为字符串类型的 s
来使用,避免了显式的类型检查和强制类型转换。
举个例子:
@Test public void switchTest() { // 不是用switch根据类型判断 Object[] objects = { "Hello", "Java", "17", 666, 0.618 }; for (Object obj : objects) { if (obj instanceof Integer v) { System.out.printf("为整型 :%s %n", v); } else if (obj instanceof Float v) { System.out.printf("为Float:%s %n", v); } else if (obj instanceof Double v) { System.out.printf("为Double:%s %n", v); } else if (obj instanceof String v) { System.out.printf("为字符串:%s %n", v); } else { System.out.printf("其他类型:%s %n", obj); } } }
我们用 Switch
表达式来改造下:
@Test public void switchTest() { Object[] objects = { "Hello", 123, "World", "Java", 3.14, "skjava" }; for (Object obj: objects) { switch (obj) { case Integer v -> System.out.println("为整数型:" + v); case Float v -> System.out.println("为浮点型:" + v); case Double v -> System.out.println("为双精度浮点数:" + v); case String v -> System.out.println("为字符串:" + v); default -> System.out.println("其他类型:" + obj); } } }
相比上面的 if...else
简洁了很多。同时在 Java 17
之前,Switch
选择器表达式只支持特定类型,即基本整型数据类型byte
、short
、char
和int
;对应的装箱形式Byte
、Short
、Character
和Integer
;String
类;枚举类型。现在有了类型模式,Switch
表达式可以是任何类型啦。
null标签
当switch
允许任何引用类型的选择器表达式,那么我们需要留意null
的情况,在Java17
之前,向switch
语句传递一个null
值,会抛出一个NullPointerException
,现在可以通过类型模式,将 null 检查作为一个单独的case标签来处理,如下:
@Test public void switchTest() { Object[] objects = { "Hello", "Java", "17", 142857, 0.618 }; for (Object obj: objects) { switch (obj) { case Integer v -> System.out.println("为整数型:" + v); case Float v -> System.out.println("为浮点型:" + v); case Double v -> System.out.println("为双精度浮点数:" + v); case String v -> System.out.println("为字符串:" + v); case null -> System.out.println("为空值"); default -> System.out.println("其他类型:" + obj); } } }
case null
可以直接匹配值为 null
的情况。
守卫标签
与匹配常量值的case
标签不同,模式case
标签可以对应多个变量值。这通常会导致switch
规则右侧出现条件语句。
根据字符串长度判断诗句是五言绝句还是七言绝句,代码如下:
@Test public void switchCaseCaseTest() { String[] poems = { "千山鸟飞绝", "春城无处不飞花", "红豆生南国", "二月春风似剪刀","念奴娇" }; for (String poem : poems) { switch (poem) { case null -> System.out.println("为空值"); case String s -> { if (s.length() == 5) System.out.printf("五言绝句:%s%n", s); else if (s.length() == 7) System.out.printf("七言绝句:%s%n", s); else System.out.printf("不知道是啥:%s%n", s); } } } }
这里的问题是,使用单一模式(即类型)来区分case
就只能判断一种情况。我们只能在模式匹配中再通过if……else
判断来区分不同的情况,来对一个模式的细化。这时,我们可以是使用switch
中的when
子句指定模式case
标签的条件,例如,case String s when if (s.length() == 5)
。表示当类型为String
并且字符串长度为5的时候,我们将这种case
标签称为守卫case
标签,将布尔表达式称为保护。
@Test public void switchCaseCaseTest() { String[] poems = { "千山鸟飞绝", "春城无处不飞花", "红豆生南国", "二月春风似剪刀","念奴娇" }; for (String poem : poems) { switch (poem) { case null -> System.out.println("为空值"); case String s when s.length() == 5 -> System.out.printf("五言绝句:%s%n", s); case String s when s.length() == 7 -> System.out.printf("七言绝句:%s%n", s); case String s -> System.out.printf("不知道是啥:%s%n", s); //剩余情况,仍然走这个 } } }
使用守卫标签,我们可以编写更灵活和表达性强的代码。
2、JEP 405:Record模式(预览)
Java 14 引入预览特性 Record类提供一种简洁的语法来声明数据载体的不可变对象,主要是为了解决长期以来在 Java 中定义纯数据载体类时,代码过于繁琐的问题。在 Java 16 中转为正式特性。
模式匹配最初是用在instanceof
上,在 Java 14 作为预览特性引入的,为了解决 instanceof
在做类型匹配时需要进行强制类型转换而导致的代码冗余。
Java 19 引入 Record 模式作为预览特性,它允许在instanceof
操作中使用记录模式,直接解构和匹配记录中的字段。
比如有一个记录Record Point(int x, int y)
,可以使用 Record 模式直接检查和提取 x
和 y
值:
if (obj instanceof Point(int x, int y)) { System.out.println(x+y); }
可以看出,类型判断、类型转换、Record变量赋值一气呵成,极大地简化了代码结构。
该特性使Java 模式匹配能力得到进一步扩展。
3、JEP 422:Linux/RISC-V移植
将JDK
移植到Linux/RISC-V
。RISC-V
是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。
4、JEP 424:外部函数和内存 API(预览)
JEP 424 (core-libs
)
这是一个预览特性。
功能进化
java版本 | 特性类型 | JEP | 特性 |
---|---|---|---|
Java 14 | 孵化特性 | JEP 370 | 引入了外部内存访问 API作为孵化特性 |
Java 15 | 第二次孵化 | JEP 383 | 优化外部内存访问 API |
Java 16 | 孵化特性 | JEP 389 | 引入了外部链接器 API |
Java 16 | 第三次孵化 | JEP 393 | 功能优化 |
Java 17 | 孵化特性 | JEP 412 | 引入了外部函数和内存 API |
Java 18 | 第二次孵化 | JEP 419 | 改进 |
Java 19 | 预览特性 | JEP 424 | 改进 |
外部函数和内存 API 是在 Java 17 中作为孵化器引入的,它提供对本机代码的静态类型的纯Java访问,其主要目的是改善 Java 与本地代码(如 C 或 C++)的互操作性。此API
与Foreign-Memory API
(JEP 393)一起,将大大简化绑定到本机库的错误处理过程。
一般Java想要调用本地代码需要使用Java Native Interface (JNI)
,但是JNI
操作比较复杂而且性能有限。
外部函数和内存API
提供了一套更简洁的API
,用于调用本地函数和处理本地内存,降低了复杂性,而且还设计了更多的安全保护措施,降低了内存泄露和应用崩溃的风险。
主要是通过两个组件实现的:
-
Foreign Function Interface (FFI): 允许 Java 代码直接调用非 Java 代码,比如 C/C++ 代码。
-
Foreign Memory Access API:提供了一种安全的方法来访问不受
JVM
管理的内存。
5、JEP 425:虚拟线程(预览)
JEP 425 (core-libs/java.lang
)
将虚拟线程引入Java平台。虚拟线程是轻量级线程,可以显著减少编写、维护和观察高吞吐量并发应用程序的工作量。
虚拟线程是一种轻量级的线程,也就是我们俗称的协程。它的资源分配和调度由VM
实现,而不是操作系统。虚拟线程的主要特点包括:
-
轻量级:与传统线程相比,它更轻量,创建和销毁的成本较低。
-
简化并发编程:由于不受操作系统线程数量的限制,我们可以为每个独立的任务创建一个虚拟线程,简化并发编程模型。
6、JEP 426:向量API(第四次孵化)
JEP 426 (core-libs
)
功能进化
java版本 | 特性类型 | JEP | 特性 |
---|---|---|---|
Java 16 | 第一次孵化 | JEP 338 | 提供一个平台无关的方式来表达向量计算,能够充分利用现代处理器上的向量硬件指令。 |
Java 17 | 第二次孵化 | JEP 414 | 改进 |
Java 18 | 第三次孵化 | JEP 417 | 进一步增强 |
Java 19 | 第四次孵化 | JEP 426 | 进一步增强 |
向量 API 是在 Java 16 中作为孵化特性引入的。
引入API来表示向量计算,这些向量计算在运行时可靠地编译为支持的CPU架构上的最佳向量指令,从而实现优于等效标量计算的性能。Java 18 对向量 API 进行了进一步的改进和增强,以更好地利用硬件功能,提高 Java 在数值计算和机器学习等领域的性能。
7、JEP 428:结构化并发(孵化特性)
这是一个孵化特性。
通过引入用于结构化并发的API来简化多线程编程。结构化并发将在不同线程中运行的多个任务视为一个工作单元,从而简化错误处理和消除,提高可靠性,并增强可观察性。
8、移除的APIs、工具、容器
参考: