New Features of Java 23

2025年5月3日 | 阅读 11 分钟

Oracle 公司将于 2024 年 9 月 17 日发布 **Java Development Kit (JDK) 23**。这是一个备受期待的版本。它包含各种 **新特性**、**增强功能** 和 **更新**。新的增强功能提高了 **性能**、**安全性** 以及 **开发人员** 的整体体验。

此版本目前处于 **初始发布候选版** 阶段。这意味着特性和更新正在开发中,但尚未最终确定。此版本专为 **Java 编程** 构建,并进行了先进的 **性能优化**、尖端的 **安全措施** 和改进的工具支持。

在本节中,我们将详细介绍 **JDK 23** 的内容,包括 **新特性**、重要**新增功能**以及相对于 **JDK 22** 的**升级**。

Java 23 包含以下十二项特性和增强功能:

455:模式、instanceof 和 switch 中的原始类型

466:类文件 API

467:Markdown 文档注释

469:Vector API

473:Stream Gatherers

471:弃用 sun.misc.Unsafe 中的内存访问方法以供移除

474:ZGC:默认启用分代模式

476:模块导入声明

477:隐式声明类和实例 main 方法

480:结构化并发

481:作用域值

482:灵活的构造函数体

让我们详细讨论每个特性和增强功能。

1. 增强的原始类型模式

Java 23 为模式匹配功能带来了一些最有前景的扩展,将原始类型纳入了 instanceof 和 switch 语句。这项特性简化了语法并减少了样板代码,允许开发人员使用不同的数据类型,而无需进行类型断言。

好处

  • 减少代码冗余和常见操作的耗时。
  • 降低了复杂性,提高了清晰度,并易于长期修改。
  • 降低了因类型识别错误而导致的运行时错误的可能性。

用例

通过这种方式,在处理不同类型的对象时,使用增强的原始类型模式可以避免额外的繁琐类型区分,尤其是在 switch-case 结构中。

文件名:PrimitivePatternExample.java

输出

 
Integer: 42   

2. 灵活的构造函数体

它们允许开发人员在构造函数的 this() 或 super() 之前放置非引用代码语句。此增强功能在创建对象时提供了更具体的访问权限,减少了直接与正在初始化的对象相关的设置逻辑。

好处

  • 将构造函数定义进一步扩展到表达式的形式。
  • 能够在对象实际创建前执行初始化操作。
  • 人们擅长识别对象初始化所需的复杂规则集并简化它们。

用例

当某些条件或计算必须在调用另一个构造函数或超类构造函数之前执行时,此特性最为有用,可以使代码更清晰、组织更好。

文件名:FlexibleConstructor.java

输出

 
Value: 10   

3. 简化的模块导入声明

Java 23 提供了新的导入语法,无需列举模块内的所有包即可导入整个模块。此更改极大地简化了在模块化应用程序中处理依赖模块的过程。

好处

  • 减少了在编译不同模块时通常观察到的重复/冗余代码量。
  • 可能更容易管理具有大量相互依赖任务的大型项目。
  • 更深入地理解模块之间的依赖关系。

用例

在需要某个特定模块的多个包的大型应用程序中,这降低了导入的复杂性,并鼓励程序员专注于功能而不是导入。

示例

4. 结构化并发

结构化并发添加了一个新的 API 概念,系统将不同线程中工作的多个相关任务视为一个单一的工作单元。这种方法简化了错误处理以及如何将取消传播到多个 异步 任务,从而提高了可靠性。

好处

  • 增强了对多项活动的通用错误控制。
  • 降低了取消策略的复杂性和灵活性。
  • 对其他并行活动的观察带来了更好的资源利用率,从而更好地管理资源。

用例

因此,结构化并发最需要用于必须执行许多并发操作的应用程序,例如 Web 服务器或 API,以处理数据管道;例如,在重叠执行期间,管理任务的生命周期或错误可能会使情况复杂化。

文件名:StructuredConcurrencyExample.java

输出

 
User: Alice, Order: 12345   

执行步骤

1. 启用预览功能进行编译

2. 启用预览功能运行

5. Stream Gatherers

Stream gatherers 通过添加中间自定义操作的能力,为 Java Stream API 增加了灵活性。此功能允许构建复杂的数据处理流,并对数据在流计算过程中如何处理拥有更大的控制权。

好处

  • 增强了流操作的灵活性和更多选项。
  • 第三方缓存的可定制聚合功能特别适合某些操作,这些操作可以使用所用应用程序内编程语言的内置编程结构轻松实现。
  • 在操作数据集合时改进了功能。

用例

当需要 Stream 上下文中默认操作未涵盖的进一步聚合或转换逻辑时,可以使用 Stream gatherers,例如,用于分组的属性的唯一值。

文件名:StreamGathererExample.java

输出

 
{a=[apple], b=[banana], c=[cherry]}   

6. Markdown 文档注释

JavaDoc 已更新,支持使用 markdown 文档注释而不是 HTML 文档标签进行文档记录,从而使文档更容易为程序员编写。

好处

  • 方便编写文档。
  • 更好的文档注释格式。
  • 改进的界面布局,清晰显示信息内容。

用例

在代码中使用 Markdown 进行文档注释有助于开发人员使 API 文档在视觉上更简洁明了,从而使用户了解如何使用类或方法。

7. 分代 ZGC

Z Garbage Collector (ZGC) 从此版本开始默认以分代模式运行。此更改通过在垃圾收集过程中将年轻代和老年代分开,增强了内存分配。

好处

  • 这是由于:缩短了垃圾收集时的暂停时间。
  • 针对需要最小化操作延迟的目的,提出了并实现了更高的效率。
  • 优化了内存使用和存储空间操作。

用例

由于分代 ZGC 为即时响应和低延迟敏感型应用程序(如实时处理或大型 Web 处理应用程序,其中标准性能至关重要)提供了良好的功能。

8. 作用域值

作用域值能够将不可更改的数据在线程内及其子线程的方法之间传递。它提供了比传统的线程局部变量更好的解决方案,但同时保持了它们的不可变性。

好处

  • 与每线程存储的线程局部变量相比,开销更低,线程局部变量具有不同的存储机制,主要在处理器的缓存中。
  • 它们还实现了使跨线程传递的数据更容易共享而不会影响可变状态的目标。
  • 与虚拟线程一起使用时,操作系统性能将得到增强。

用例

当处理需要保持不变且在不同线程间有效共享而不会被其他 方法修改的标记时,它变得很有用;本质上,当用作常量或可以在程序其他部分使用的设置时,这些值非常方便。

文件名:ScopedValuesExample.java

输出

 
Scoped Value: Initial Value
Scoped Value in another thread: Initial Value   

9. 类文件 API

Java 中的类文件 API 是一个方便的工具,能够读取和操作 Java 源文件以及它们的写入。此 API 用于分析或转换字节码的工具;它提供了一种在程序内访问类文件中定义的类、方法和字段的许多方面的方法。类文件 API 可用于构建类分析器、转换器和生成器,以及 字节码

好处

  1. 允许创建更复杂的 软件 工具,这些工具对于程序分析和转换是必需的。
  2. 支持运行时更改和动态类生成。
  3. 有助于学习 Java 类构建和功能的原理。

用例

例如,开发人员可以使用类文件 API 来构建一个检测类依赖关系的应用程序,或者一个从类文件结构自动生成文档的应用程序。以下是一个读取类文件的简单示例:

文件名:ClassFileReader.java

输出

 
Class file read successfully: MyClass.class   

10. Vector API

Java 中的 Vector API 包含一个对象,用于模拟 Java 程序中的 SIMD(单指令多数据)指令。自 Java 16 起实现,并在后续版本中进行了额外更新,此 API 允许程序员编写矢量化代码,而无需了解使用 SIMD 指令的细节。

好处

  1. 通过利用当今 CPU 的并行计算特性,在数值计算方面实现显著的收益。
  2. 降低了实际使用复杂算法的难度,因为它为实现矢量计算提供了一个清晰且有说服力的 API。
  3. 提供了一种独立于平台的机制,可与多种 CPU 架构一起使用。

用例

Vector API 的功能在 机器学习密码学 或线性代数等领域尤其有价值。以下是一个使用 Vector API 对两个数组进行相加的示例:

文件名:VectorAddition.java

输出

 
Result: [1.8926005, 1.3122721, 1.0168884, 0.80259097, 0.8667154, 1.0061616, 0.6949272, 0.483315]   

执行步骤

编译

运行

11. 弃用 sun.misc.Unsafe 中的内存访问方法以供移除

Sun.misc.Unsafe 类一直是一个 Java 的“出口”,因为它可能进行 内存 操作,这些操作会绕过标准的安全机制。由于软件行业的进步,该类已弃用了一些内存访问方法,这些方法将在后续的 Java 版本中逐步淘汰。此举旨在帮助开发人员寻找标准库提供的更好的替代方案。

好处

先前的工作表明,它可以消除内存损坏或其他不安全的操作。

鼓励使用更安全、遵循 Java 原则的 API。

这是有益的,因为它消除了难以学习且风险较高的 Java API,这些 API 很少使用。

用例

不鼓励不安全的内存访问,并建议开发人员转向更安全的构造,如 ByteBuffer 或标准库的某些功能。例如:

文件名:SafeMemoryAccess.java

输出

 
Value from ByteBuffer: 42   

12. 隐式声明类和实例 main 方法

从 Java 22 开始,Java 中出现了隐式声明类和实例 main 方法,这改进了可执行程序的定义方式。此特性使开发人员能够在不需要显式 public class 和 static main 方法的情况下编写程序。

好处

  1. 减少了程序中非关键元素的混乱。
  2. 增加了许多新开发人员开始编码的可能性,而无需担心类结构。
  3. 提供了一种更自然的组织代码的方式,而不受限于框架的特定严格规定。

用例

  1. 开发人员现在可以按如下方式定义一个简单的可执行程序:

文件名:HelloWorld.java

输出

 
Hello, World!   

执行步骤

编译

运行

结论

Java 23 为语言集带来了新的强大修饰符,这些修饰符有助于提高可用性、速度和表达力。改进的原始类型模式扩展了可以与原始类型匹配的模式类型。虽然灵活的构造函数体不允许构造类的对象,但它们在这样做时具有一定的灵活性。

简化的模块导入解决了模块化应用程序中的依赖管理问题。结构化并发增强了多线程范式中功能实现期间的错误和任务控制。Stream Gatherers 在 Stream API 中提供了用户定义的函数,并增加了强大的数据处理特性。

Markdown 文档注释增强了编写文档的便利性,并提高了文档的可读性。分代 ZGC 为需要低延迟的应用程序提供了用于高效内存使用的垃圾收集器,而作用域值有助于更轻松地在多个线程之间传递数据。总而言之,这些特性使 Java 成为一种更现代的语言,并有效地优化了语言以适应开发人员的需求。