Java 21 是 Java 17 之后的下一个 LTS 版本。虚拟线程在 Java 21 中将成为正式功能。可以预期的是,Java 21 会成为一个很流行的 Java 版本。
Java 21 将在 2023 年 9 月 19 日发布。目前 Java 21 包含的内容已经基本确定了。下面来梳理一下 Java 21 中会包含的内容。
正式功能
虚拟线程 (Virtual Threads)
自从 Java 19 中引入之后,虚拟线程已经成为了 Java 社区中火热的话题。虚拟线程会改变 Java 的多线程编程。虚拟线程会成为 Java 21 的杀手锏功能,促使更多用户升级到 Java 21。
顺序集合(Sequenced Collections)
顺序集合中的元素有确定的出现顺序(encounter order)。Java 21 新增了与顺序集合相关的接口,统一了与顺序集合相关的操作,包括获取第一个和最后一个元素,在集合的头部和尾部插入和删除元素,以及逆序遍历集合等。
新增的顺序集合相关的接口包括 SequencedCollection
、SequencedSet
和 SequencedMap
。Java 集合框架中的已有类也进行了调整。更新之后的集合框架的类结构如下图所示。
记录类型的模式(Record Patterns)
记录类型的模式可以解构记录对象中的值,可以方便地提取记录中的组件。
比如下面的记录类型 Point
:
record Point(int x, int y) {}
通过下面的方式就可以解构出 Point
中的组件 x
和 y
。
static void printSum(Object obj) { if (obj instanceof Point(int x, int y)) { System.out.println(x + y); }}
switch 的模式匹配(Pattern Matching for switch)
增强 Java 中的 switch 表达式和语句,允许在 case 标签中使用模式。当模式匹配时,执行 case 标签对应的代码。
在下面的代码中,switch 表达式使用了类型模式来进行匹配。
static String formatterPatternSwitch(Object obj) { return switch (obj) { case Integer i -> String.format("int %d", i); case Long l -> String.format("long %d", l); case Double d -> String.format("double %f", d); case String s -> String.format("String %s", s); default -> obj.toString(); };}
分代式 ZGC (Generational ZGC)
增强 Z 垃圾回收器(ZGC)来支持不同的世代。年轻和年老的对象分别存放在不同的世代中,使得年轻的对象可以更加频繁的被回收。
废弃 Windows 32 位版本(Deprecate the Windows 32-bit x86 Port for Removal)
废弃 Windows 32 位 x86 版本,将在以后的 OpenJDK 版本中删除。之所以废弃 Windows 32位 x86 版本, 主要有几个动机:
Windows 10,支持 32 位的最后一个 Windows 操作系统,将在2025年10月终止。结束对 Windows 32位 x86 版本的支持,可以把精力转移到更加重要的事情上。
另外一个原因是,虚拟线程在 Windows 32 位 x86 版本的实现回退到了使用内核线程,没办法享受到 Loom 项目带来的好处。
预览功能
未命名类和实例 main 方法 (Unnamed Classes and Instance Main Methods)
该 JEP 的目标是简化 Java 的入口类。一直以来,Java 的入口类的 main
方法的声明有着很严格的要求,必须是 public static void main(String[] args)
。对于 Java 初学者来说,这个 main
方法的声明引入了太多的 Java 语法概念,不利于初学者快速上手。
在经过简化之后,不再对 main
方法的声明进行严格的限制,而是允许多种声明方式。具体来说, 在启动的入口类中会按照如下顺序依次查找 main
方法:
首先是
public static void main(String[] args)
方法,其次是声明为 protected 或 package 的
static void main(String[] args)
方法,接着是非私有的
static void main()
方法,然后是非私有的实例方法
void main(String[] args)
,最后是非私有的实例方法
void main()
。
对于后面两种情况,由于调用的是实例方法,需要有入口类的实例。这就要求入口类有一个非私有的,不带任何参数的构造方法。在启动时,首先创建出入口类的对象,再调用对象的 main
方法。
未命名类允许省略外层的 Java 类声明,直接把 main
方法作为顶层元素,写在 Java 源代码文件中。main
方法所依赖的其他方法和字段,也同样作为顶层元素。Java 编译器会自动生成一个匿名类,并调用其中的 main
方法。
在对入口类进行简化之后,只需要下面的代码就可以了。
void main() { System.out.println("Hello, World!");}
字符串模板 (String Templates)
字符串模板是 Java 一直以来缺少的功能。Java 21 的字符串模板是一个通用的实现,可以把任何字符串转换成任意类型的对象。
字符串模板的实现由两个部分组成,分别是 StringTemplate
表示的模板,以及 StringTemplate.Processor
表示的模板处理器。StringTemplate
表示的模板中包含需要求值的表达式,如 \{name}
表示获取 name
的值。
Java 内置提供了几个模板处理器的实现。STR
用来对包含表达式的字符串模板进行求值。这是通常意义上的字符串模板的用法。
int x = 10, y = 20;String s = STR."\{x} + \{y} = \{x + y}";
FMT
可以进行格式化,使用的是 java.util.Formatter
支持的语法。
record Rectangle(String name, double width, double height) { double area() { return width * height; }}Rectangle[] zone = new Rectangle[] { new Rectangle("Alfa", 17.8, 31.4), new Rectangle("Bravo", 9.6, 12.4), new Rectangle("Charlie", 7.1, 11.23),};String table = FMT.""" Description Width Height Area %-12s\{zone[0].name} %7.2f\{zone[0].width} %7.2f\{zone[0].height} %7.2f\{zone[0].area()} %-12s\{zone[1].name} %7.2f\{zone[1].width} %7.2f\{zone[1].height} %7.2f\{zone[1].area()} %-12s\{zone[2].name} %7.2f\{zone[2].width} %7.2f\{zone[2].height} %7.2f\{zone[2].area()} \{" ".repeat(28)} Total %7.2f\{zone[0].area() + zone[1].area() + zone[2].area()} """;
RAW
生成一个不对字符串做任何处理的 StringTemplate
对象。
可以创建自定义的字符串模板处理器来生成非 String
类型的对象。下面代码中的 JSON
从字符串模板中生成 JSONObject
对象。
var JSON = StringTemplate.Processor.of( (StringTemplate st) -> new JSONObject(st.interpolate()) );
未命名模式和变量 (Unnamed Patterns and Variables)
下划线终于来了。可以使用下划线表示未命名的变量,以及模式匹配时不使用的组件。
未命名变量的典型场景是 try-with-resources
语句和 catch
子句中的异常变量。
try (var _ = ScopedContext.acquire()) { }
try { ... } catch (Exception _) { ... } catch (Throwable _) { ... }
未命名模式是一个无条件的模式,并不绑定任何值。未命名模式变量出现在类型模式中。
if (r instanceof ColoredPoint(_, Color c)) { ... c ... }switch (b) { case Box(RedBall _), Box(BlueBall _) -> processBox(b); case Box(GreenBall _) -> stopProcessing(); case Box(_) -> pickAnotherBox();}
外部方法和内存 API (Foreign Function & Memory API)
外部方法和内存 API提供了一种新的方式来与 Java 运行时之外的代码和数据来进行互操作。该 API 可以高效调用外部方法,并安全访问外部内存。该 API 用来替代 JNI。
Java 21 中是该 API 的第 3 个预览版。
孵化功能
矢量 API (Vector API)
Vector API 是 OpenJDK 中 Panama 项目的一部分。Vector API 的作用是描述矢量计算,并在运行时编译成 CPU 架构上的矢量计算指令。
矢量是一组标量值的序列。标量值的数量取决于硬件定义的 vector lane 的数量。在对两个矢量进行计算时,会在每条 lane 上对两个矢量相应的标量值进行计算。通过并行计算,两个矢量计算的速度与单个标量值的计算速度是相同的,极大地提高了计算速度。这被称为 SIMD(Single Instruction Multiple Data),单指令多数据。
HotSpot 虚拟机已经支持自动的矢量化,但是存在很大的局限性,开发人员难以有效的利用。Vector API 提供了一种方式来编写复杂的矢量算法。虽然底层仍然使用的是 HotSpot 的自动矢量化,但是矢量化的结果更加可靠。
试验功能
分代式 Shenandoah(Generational Shenandoah)
为垃圾回收器 Shenandoah 增加了分代式支持。
来源地址:https://blog.csdn.net/cheng_fu/article/details/130920087