Java 22新特性(2024年3月)
正式特性
外部函数与内存 API
Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。
外部函数与内存 API(FFM API)提供了标准化、类型安全的方式来从 Java 直接调用本地代码,并在 Java 侧描述函数签名和内存布局。比起 JNl,FFM 一般不需要编写 JNI胶水代码,调用链更简洁、可维护性更好
让我们看看用 FFM API 是怎么做的
这里有几个关键概念需要理解
Linker 负责连接 Java 代码和本地代码
SymbolLookup 用来查找本地库中的函数
MethodHandle 是 Java 中已有的概念,表示本地函数的调用
要特别注意的是 Arena.ofconfined(),这是 FFM AP 中一个非常重要的内存管理概念。Arena 可以理解为一个内存管理区域,它控制着内存的生命周期。当你使用 try-with-resources 语句时,Arena 会在代码块结束时自动释放所有相关的内存资源,这样就避免了内存泄漏的问题。
FFM API还有一个强大的特性是 支持双向调用。不仅可以从 Java 调用C函数,还可以把 Java 方法作为函数指针传递给 C函数。比如你可以用 Java 写一个比较器,然后传给 C标准库的 qsort 函数
FFM API现在支持几乎所有主流平台,性能相比 JN!可能有一定提升,特别是在频繁调用本地函数的场景下。
内存管理示例
未命名模式和变量
未命名模式和变量使得我们可以使用下划线 _ 表示未命名的变量以及模式匹配时不使用的组件,旨在提高代码的可读性和可维护性。
未命名变量的典型场景是 try-with-resources 语句、 catch 子句中的异常变量和for循环。当变量不需要使用的时候就可以使用下划线 _代替,这样清晰标识未被使用的变量。
未命名模式是一个无条件的模式,并不绑定任何值。未命名模式变量出现在类型模式中。
以下场景可以使用Unnamed Variables
局部变量
try-with-resource
循环头中声明的变量
catch中声明的变量
lambda表达式中的参数
G1 的区域固定
Java 22 改进了 G1 垃圾收集器,引入了区域固定功能
这个改进主要影响
本地内存交互:减少 GC 对本地代码的影响.。大对象处理:改善大对象的 GC 性能
延迟优化:减少某些 GC 暂停
启动多文件源代码程序
Java 22 扩展了单文件源代码程序的功能,现在支持多文件
这个特性让原型开发和脚本编写更加方便
预览特性
灵活的构造函数体(预览)
其实就是在super()上面可以添加代码了,目前还是预览状态
以前java语法规定了倘若使用super调用父类构造方法时,其必须出现在第一行,这有时就不利于我们编写更健壮的程序,比如:下面代码编译报错:
为了解决上面的问题,在java22中提出了pre-construction context,它允许我们在super()上面编写不访问对象的代码。
也就是:
允许super(…)和this(…) 之前添加别的语句
限制仍然存在
构造器自顶向下
字段在完成初始化之前不能被访问
依靠编译器的检查:根据编译错误来修改
示例代码1
示例代码2
字符串模板(第二次预览)
String Templates(字符串模板) 在 JDK21 中第一次预览,JDK22 是第二次预览。在JDK23中被撤回了
String Templates 提供了一种更简洁、更直观的方式来动态构建字符串。通过使用占位符${},我们可以将变量的值直接嵌入到字符串中,而不需要手动处理。在运行时,Java 编译器会将这些占位符替换为实际的变量值。并且,表达式支持局部变量、静态/非静态字段甚至方法、计算结果等特性。
实际上,String Templates(字符串模板)再大多数编程语言中都存在:
Java 在没有 String Templates 之前,通常使用字符串拼接或格式化方法来构建字符串:
这些方法或多或少都存在一些缺点,比如难以阅读、冗长、复杂。
Java 使用 String Templates 进行字符串拼接,可以直接在字符串中嵌入表达式,而无需进行额外的处理:
在上面的模板表达式中:
STR 是模板处理器。
{name}为表达式,运行时,这些表达式将被相应的变量值替换。
Java 目前支持三种模板处理器:
STR:自动执行字符串插值,即将模板中的每个嵌入式表达式替换为其值(转换为字符串)。
FMT:和 STR 类似,但是它还可以接受格式说明符,这些格式说明符出现在嵌入式表达式的左边,用来控制输出的样式
RAW:不会像 STR 和 FMT 模板处理器那样自动处理字符串模板,而是返回一个 StringTemplate 对象,这个对象包含了模板中的文本和表达式的信息
除了 JDK 自带的三种模板处理器外,你还可以实现 StringTemplate.Processor 接口来创建自己的模板处理器。
我们可以使用局部变量、静态/非静态字段甚至方法作为嵌入表达式:
还可以在表达式中执行计算并打印结果:
为了提高可读性,可以将嵌入的表达式分成多行:
类文件 API(预览)
Java 22 引入了类文件 API 作为预览特性,提供了读取、分析和生成 Java 类文件的标准方法
Stream Gatherers
Java 22 引入了 Stream Gatherers 作为预览特性
结构化并发(第二次预览)
Java 22 继续完善结构化并发
孵化器特性
向量 API(第七次孵化器)
Java 22 继续改进向量 API
Java 23新特性(2024年9月)
正式特性
ZGC:默认的分代模式
ZGC垃圾回收器 (ZGC) 的默认模式切换为分代模式,并弃用非分代模式,计划在未来版本中移除。这是因为分代 ZGC 是大多数场景下的更优选择。
Markdown 文档注释
在 JavaDoc 文档注释中可以使用 Markdown 语法,取代原本只能使用 HTML 和 JavaDoc 标签的方式。
Markdown 更简洁易读,减少了手动编写 HTML 的繁琐,同时保留了对 HTML 元素和 JavaDoc 标签的支持。这个增强旨在让 API 文档注释的编写和阅读变得更加轻松,同时不会影响现有注释的解释。Markdown 提供了对常见文档元素(如段落、列表、链接等)的简化表达方式,提升了文档注释的可维护性和开发者体验。
弃用 sun.misc.Unsafe 中的内存访问方法
JEP 471 提议弃用 sun.misc.Unsafe 中的内存访问方法,这些方法将来的版本中会被移除。
这些不安全的方法已有安全高效的替代方案:
java.lang.invoke.VarHandle:JDK 9 (JEP 193) 中引入,提供了一种安全有效地操作堆内存的方法,包括对象的字段、类的静态字段以及数组元素。java.lang.foreign.MemorySegment:JDK 22 (JEP 454) 中引入,提供了一种安全有效地访问堆外内存的方法,有时会与VarHandle协同工作。
这两个类是 Foreign Function & Memory API(外部函数和内存 API) 的核心组件,分别用于管理和操作堆外内存。Foreign Function & Memory API 在 JDK 22 中正式转正,成为标准特性。
javac 中默认禁用注解处理
从 JDK23 开始,只有在显式配置注解处理或在 javac 命令行上显式请求运行注解处理时,才会运行注解处理。这和当前的默认行为不同,现有默认行为是在没有显式注解处理相关选项的情况下,通过搜索类路径中的处理器来运行注解处理。
预览特性
模式中的原始类型、instanceof 和 switch 中支持原始类型(预览)
在 JEP 455 之前, instanceof 只支持引用类型,switch 表达式和语句的 case 标签只能使用整数字面量、枚举常量和字符串字面量。
JEP 455 的预览特性中,instanceof 和 switch 全面支持所有原始类型,包括 byte, short, char, int, long, float, double, boolean。
类文件 API(第二次预览)
类文件 API 在 JDK 22 进行了第一次预览,由 JEP 457 提出。
类文件 API 的目标是提供一套标准化的 API,用于解析、生成和转换 Java 类文件,取代过去对第三方库(如 ASM)在类文件处理上的依赖。
Stream Gatherers(第二次预览)
流收集器在 JDK 22 进行了第一次预览,由 JEP 461 提出。
预览版功能:可以自定义中间操作了
原版stream流存在的问题
只能使用Stream类提供的方法,不能随意添加
distinct 只能根据对象相等性来去重,无法根据对象的属性值来去重
模块导入声明 (预览)
模块导入声明允许在 Java 代码中简洁地导入整个模块的所有导出包,而无需逐个声明包的导入。这一特性简化了模块化库的重用,特别是在使用多个模块时,避免了大量的包导入声明,使得开发者可以更方便地访问第三方库和 Java 基本类。
此特性对初学者和原型开发尤为有用,因为它无需开发者将自己的代码模块化,同时保留了对传统导入方式的兼容性,提升了开发效率和代码可读性。
但是如果同一个模块中出现了同名的类,那么就必须恢复到之前的写法,显式导入了。
未命名类和实例 main 方法 (第三次预览)
Java21第一次预览,这个特性主要简化了 main 方法的的声明。对于 Java 初学者来说,这个 main 方法的声明引入了太多的 Java 语法概念,不利于初学者快速上手。
没有使用该特性之前定义一个 main 方法:
使用该新特性之后定义一个 main 方法:
进一步简化(未命名的类允许我们省略类名)
这里连类都没有了,隐式声明类继承自 Object,不实现接口,并且不能在源代码中按名称引用。此外,实例主方法也不再强制要求它们是 static 或 public 的,并且不带参数的方法也可以作为有效的程序入口点。
结构化并发 (第三次预览)
Java 19 引入了结构化并发,一种多线程编程方法,目的是为了通过结构化并发 API 来简化多线程编程,并不是为了取代java.util.concurrent,目前处于孵化器阶段。
结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。也就是说,结构化并发保留了单线程代码的可读性、可维护性和可观察性。
结构化并发的基本 API 是StructuredTaskScope。StructuredTaskScope 支持将任务拆分为多个并发子任务,在它们自己的线程中执行,并且子任务必须在主任务继续之前完成。
StructuredTaskScope 的基本用法如下:
结构化并发非常适合虚拟线程,虚拟线程是 JDK 实现的轻量级线程。许多虚拟线程共享同一个操作系统线程,从而允许非常多的虚拟线程。
作用域值 (第三次预览)
引入作用域值,它使得方法能够在线程内及其调用者之间共享不可变数据,以及与子线程共享。作用域值比线程局部变量更容易理解。当与虚拟线程(JEP 444)和结构化并发(JEP 480)一起使用时,它们还具有更低的空间和时间成本。
作用域值允许在大型程序中的组件之间安全有效地共享数据,而无需求助于方法参数。
灵活的构造函数体(第二次预览)
这个特性最初在 JDK 22 由 JEP 447: Statements before super(…) (Preview)提出。
Java 要求在构造函数中,super(...) 或 this(...) 调用必须作为第一条语句出现。这意味着我们无法在调用父类构造函数之前在子类构造函数中直接初始化字段。
灵活的构造函数体解决了这一问题,它允许在构造函数体内,在调用 super(..) 或 this(..) 之前编写语句,这些语句可以初始化字段,但不能引用正在构造的实例。这样可以防止在父类构造函数中调用子类方法时,子类的字段未被正确初始化,增强了类构造的可靠性。
这一特性解决了之前 Java 语法限制了构造函数代码组织的问题,让开发者能够更自由、更自然地表达构造函数的行为,例如在构造函数中直接进行参数验证、准备和共享,而无需依赖辅助方法或构造函数,提高了代码的可读性和可维护性。
字符串模板(撤回的JEP)
字符串模板首次在 JDK21 (JEP430) 中预览,并在 JDK22 (JEP 459) 中再次预览。经过反馈和广泛讨论,得出结论,该特性在当前形式下不适合。目前还没有更好的设计共识,因此暂时撤回了该特性,JDK23 将不包含它。
孵化器特性
向量 API(第八次孵化)
向量计算由对向量的一系列操作组成。向量 API 用来表达向量计算,该计算可以在运行时可靠地编译为支持的 CPU 架构上的最佳向量指令,从而实现优于等效标量计算的性能。
向量 API 的目标是为用户提供简洁易用且与平台无关的表达范围广泛的向量计算。
这是对数组元素的简单标量计算:
这是使用 Vector API 进行的等效向量计算:
Java 24新特性(2025年3月)
正式特性
类文件 API
类文件 API是一个专为框架和工具开发者设计的强大特性。长期以来,如果你想要在运行时动态生成、分析或修改 Java 字节码,就必须依赖像 ASM、Javassist 或者 CGLIB 这样的第三方库。 而且操作字节码需要深入了解底层细节,学习难度很大,我只能借助 AI 来搞定。
有了类文件 API,操作字节码变得简单了一些
读取和分析现有的类文件也很简单
第三方字节码库可能需要一段时间才能跟上新特性的变化,而官方的类文件 API则能够与语言特性同步发布,确保开发者能够使用最新的字节码功能。
实际应用示例
流收集器
Stream Gatherers API(JEP 461扩展)
流收集器 Stream::gather(Gatherer) 是一个强大的新特性,它允许开发者定义自定义的中间操作,从而实现更复杂、更灵活的数据转换。Gatherer 接口是该特性的核心,它定义了如何从流中收集元素,维护中间状态,并在处理过程中生成结果。例如,可以使用 Stream::gather 实现滑动窗口、自定义规则的去重、或者更复杂的状态转换和聚合。
复杂流处理示例:
新增内置Gatherers:
fold():实现可变状态聚合scan():生成中间结果的流fixedWindow():固定大小批处理
性能特性:
比传统collect操作减少40%的中间集合分配
支持短路操作优化
除了内置的 Gatherers 外,还可以自定义 Gatherer,举一个最简单的例子 –给每个元素添加前缀。先自定义一个Gatherer
这个例子展示了 Gatherer 的最基本形态
不需要状态:第一个参数返回 nu,因为我们不需要维护任何状态
简单转换:第二个参数接收每个元素,做简单处理后推送到下游。
无需收尾:省略第三个参数,因为不需要最终处理虽然这个例子用 map()也能实现,但它帮助我们理解了 Gatherer 的基本工作机制。
这就是 Stream Gatherers 强大之处,它能够维护复杂的内部状态,并根据业务逻辑灵活地向下游推送结果,让原本需要手动循环的复杂逻辑变得简洁优雅。
Stream Gatherers 的另一个优势是它和现有的 Stream API完全兼容。你可以在 Stream 管道中的任何位置插入 Gatherer 操作,就像使用 map、filter 或 collect 一样自然,让复杂的数据处理变得既强大又优雅。
实际应用示例
删除 Windows 32 位 x86 端囗
Java 24 正式移除了对 Windows 32 位系统的支持
提前类加载和链接
Java 24 引入了提前类加载和链接功能,可以在应用启动前预加载类
这个特性可以
减少启动时间:预加载常用类
提高缓存命中率:类信息提前准备
优化内存布局:更好的内存分配策略
永久禁用安全管理器
安全性管理器(Security Manager)并不是Java客户端代码的主要安全手段,也极少用于服务器端代码。此外,维护它成本高昂。因此,在Java 17中通过JEP 411: Deprecate the Security Manager for Removal将其弃用以备移除。本特性则完全禁止开发者启用安全性管理器,Security Manager API将在未来的版本中被移除。
ZGC 删除非分代模式
Java 24 完全移除了 ZGC 的非分代模式
G1垃圾回收器屏障优化提高效率
JEP 475: Late Barrier Expansion for G1
该特性主要是将Late Barrier Expansion引进到G1中。Barrier expansion是指在垃圾回收过程中插入或生成额外代码(称为“屏障”)以管理内存并确保垃圾回收的正确性。这些屏障通常被插入到字节码中的特定位置,例如在内存访问之前或之后,以执行以下任务:
记住写操作:跟踪对象的更改,这有助于垃圾回收器识别需要扫描的堆的部分。例如,写屏障(write barrier)会在每次存储操作之前执行,记录哪些对象被修改,从而帮助垃圾回收器维护对象的可达性信息。
保持一致性:确保程序对内存的视图与垃圾回收器的视图保持一致,特别是在并发垃圾回收阶段。例如,读屏障(read barrier)会在读取操作之前检查指针是否指向堆内存,并记录这些操作,以防止垃圾回收器误判对象的可达性。
处理引用:管理对象之间的引用,特别是在压缩或迁移阶段。例如,在垃圾回收的增量收集中,屏障可以阻止指向未分配空间(fromspace)的指针进入寄存器,从而避免垃圾回收器无法追踪到这些对象。
Early barrier expansion的含义是这些屏障在编译过程的早期插入或生成,而如果在过程的后期进行(正如JEP所提议的),则可以实现更优化的放置,并可能减少这些屏障相关的开销,具体为:
动态屏障插入:在JIT编译的优化阶段而非解析阶段插入写屏障,基于实际使用模式生成最小化屏障代码
条件屏障消除:通过逃逸分析识别不需要屏障的内存操作,在安全情况下完全省略屏障
SIMD屏障优化:对数组批量操作生成向量化屏障指令,提升批量写操作的吞吐量 基准测试显示,该优化使G1在写密集型负载下的吞吐量提升12%,同时减少JIT编译代码大小5-7%。对于使用大量
ConcurrentHashMap或CopyOnWriteArrayList的并发应用收益尤为明显。
虚拟线程的同步而不固定平台线程
JEP 491: Synchronize Virtual Threads without Pinning 优化了虚拟线程与 synchronized 的工作机制。
JDK21引入虚拟线程时还有个pinning的问题,就是当虚拟线程在其载体上运行同步代码块时,它无法从载体上卸载。比如:
如果是单纯调用storeRepo.fetchCapacity()则没问题,虚拟线程会从其载体unmount,释放平台线程给其他虚拟线程mount;但是如果是调用customerEnters,它用synchronized修饰则JVM会将该虚拟线程pin住防止其被unmount,这样子的话虚拟线程与平台线程都会blocked,直到fetchCapacity方法返回。
之所以pinning是因为synchronized依赖于monitors来确保它们只能由单个线程同时进入。在进入synchronized块之前,线程必须获取与实例相关联的monitor。JVM在平台线程级别跟踪这些monitor的所有权,而不是在虚拟线程级别跟踪。基于这些信息,假设不存在pinning,理论上,虚拟线程#1可以在synchronized块中间卸载,而虚拟线程#2可以装载到相同的平台线程上,并继续执行该synchronized块,因为承载线程是相同的,仍然持有对象的monitor。
从Java 24开始,虚拟线程可以获取、持有和释放监视器,而无需绑定到其载体线程。这意味着由于线程pinning而切换到不同的锁机制已不再是必需的。从现在起,无论是使用虚拟线程还是其他方法,性能表现都将相当一致。
在少数情况下,虚拟线程仍然会被pinning,其中一个情况是当它调用本地代码并返回到执行阻塞操作的Java代码时。在这种情况下,JDK Flight Recorder(JFR)会记录一个jdk.VirtualThreadPinned事件,如果要跟踪这些情况,可以启用JFR。
使用sun.misc.Unsafe内存访问方法时发出警告
JEP 498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe
JDK9的JEP 193: Variable Handles引入了VarHandle API用于替代sun.misc.Unsafe JDK14的JEP 370: Foreign-Memory Access API (Incubator)引入了Foreign-Memory Access API作为incubator JDK15的JEP 383: Foreign-Memory Access API (Second Incubator)Foreign-Memory Access API作为第二轮incubator JDK16的JEP 393: Foreign-Memory Access API (Third Incubator)作为第三轮,它引入了Foreign Linker API (JEP 389) FFM API在JDK 17的JEP 412: Foreign Function & Memory API (Incubator)作为incubator引入 FFM API在JDK 18的JEP 419: Foreign Function & Memory API (Second Incubator)作为第二轮incubator JDK19的JEP 424: Foreign Function & Memory API (Preview)则将FFM API作为preview API JDK20的JEP 434: Foreign Function & Memory API (Second Preview)作为第二轮preview JDK21的JEP 442: Foreign Function & Memory API (Third Preview)作为第三轮preview JDK22的JEP 454: Foreign Function & Memory API则正式发布此特性 JDK23的JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal废弃sun.misc.Unsafe,以便后续版本移除
JDK24默认情况下将在首次使用任何内存访问方法时发出警告,无论这些方法是直接调用还是通过反射调用。也就是说,无论使用了哪些内存访问方法,以及任何特定方法被调用的次数如何,最多只会发出一次警告。这将提醒应用程序开发者和用户即将移除这些方法,并需要升级库。
这些不安全的方法已有安全高效的替代方案:
java.lang.invoke.VarHandle:JDK 9 (JEP 193) 中引入,提供了一种安全有效地操作堆内存的方法,包括对象的字段、类的静态字段以及数组元素。java.lang.foreign.MemorySegment:JDK 22 (JEP 454) 中引入,提供了一种安全有效地访问堆外内存的方法,有时会与VarHandle协同工作。
这两个类是 Foreign Function & Memory API(外部函数和内存 API) 的核心组件,分别用于管理和操作堆外内存。Foreign Function & Memory API 在 JDK 22 中正式成为标准特性。
预览特性
新增密钥派生函数API支持现代加密标准
JEP 478: Key Derivation Functions API引入了符合NIST SP 800-56C标准的密钥派生实现。
随着量子计算领域的进步,传统加密算法变得更容易受到实际攻击。因此,Java平台必须整合后量子密码学(PQC),以抵御这些威胁。Java的长期目标是最终实现混合公钥加密(HPKE),以便无缝过渡到量子安全加密。JDK 21中包含的KEM API(JEP 452)是HPKE的一个组成部分,标志着Java朝着HPKE迈出的第一步,并为后量子挑战做好了准备。该JEP提出了HPKE的另一个组成部分,作为这一方向上的下一步:密钥派生函数(KDFs)的API。
使用示例如下:
该API支持:
HKDF:基于HMAC的提取-扩展密钥派生框架
PBKDF2:密码-Based密钥派生,替代已废弃的
PBEKeySpecArgon2:抗侧信道攻击的内存困难型算法 特别在微服务间TLS通信场景中,开发者现在可以标准化密钥派生流程,避免各服务实现不一致导致的安全隐患。
后量子加密技术前瞻性支持
JEP 496:Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism
引入了三种抗量子计算攻击的算法:
ML-KEM(原CRYSTALS-Kyber):基于格理论的密钥封装机制
ML-DSA(原CRYSTALS-Dilithium):数字签名算法
SLH-DSA:基于哈希的签名方案
`` 虽然这些算法尚未进入最终标准,但预览版允许金融、政务等敏感领域提前进行技术验证和性能测试,为即将到来的量子计算时代做好准备。
Scoped Values(第四次预览)
JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview JDK24则作为第四次preview,与JDK23不同的是callWhere以及runWhere方法从ScopedValue类中移除,可以使用ScopedValue.where()再链式调用run(Runnable)或者call(Callable)
并发编程模型革新:
技术对比: 特性ThreadLocalScopedValue内存泄漏风险高零子线程继承需显式传递自动继承性能开销约15ns/访问约3ns/访问
灵活构造函数体(第三次预览)
JEP 492 Flexible Constructor Bodies (Third Preview)
JDK22的JEP 447: Statements before super(…) (Preview)作为第一次preview JDK23的JEP 482: Flexible Constructor Bodies (Second Preview)作为第二次preview JDK24作为第三次preview
灵活的构造函数体允许在构造函数体内,在调用 super(..) 或 this(..) 之前编写语句,这些语句可以初始化字段,但不能引用正在构造的实例。这样可以防止在父类构造函数中调用子类方法时,子类的字段未被正确初始化,增强了类构造的可靠性。
这一特性解决了之前 Java 语法限制了构造函数代码组织的问题,让开发者能够更自由、更自然地表达构造函数的行为,例如在构造函数中直接进行参数验证、准备和共享,而无需依赖辅助方法或构造函数,提高了代码的可读性和可维护性。
原始类型模式匹配(第二次预览)
JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)
JDK19的JEP 405: Record Patterns (Preview)将Record的模式匹配作为第一次preview JDK20的JEP 432: Record Patterns (Second Preview)作为Record模式匹配第二次preview JDK21的JEP 440: Record Patterns则将Record模式匹配正式发布 JDK23的JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)将原始类型的匹配作为第一次preview JDK24作为第二次preview
技术实现:
底层优化:
字节码层面消除冗余的类型转换指令
模式变量直接绑定到原始类型而非包装类
JIT编译器可进行更激进的标量替换优化
性能影响:
数值计算密集型代码性能提升8-12%
减少50%的临时对象分配
结构化并发(第四次预览)
JEP 499: Structured Concurrency (Fourth Preview)
JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview JDK24作为第四次preview
JDK 19 引入了结构化并发,一种多线程编程方法,目的是为了通过结构化并发 API 来简化多线程编程,并不是为了取代java.util.concurrent,目前处于孵化器阶段。
结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。也就是说,结构化并发保留了单线程代码的可读性、可维护性和可观察性。
错误处理改进:
结构化并发非常适合虚拟线程,虚拟线程是 JDK 实现的轻量级线程。许多虚拟线程共享同一个操作系统线程,从而允许非常多的虚拟线程。
新增特性:
deadline支持:
scope.withDeadline(Instant.now().plusSeconds(5))嵌套scope的层次化取消
与虚拟线程深度集成
简化源文件启动(第四次预览)
JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)
没有使用该特性之前定义一个 main 方法:
使用该新特性之后定义一个 main 方法:
进一步简化(未命名的类允许我们省略类名)
这里连类都没有了,隐式声明类继承自 Object,不实现接口,并且不能在源代码中按名称引用。此外,实例主方法也不再强制要求它们是 static 或 public 的,并且不带参数的方法也可以作为有效的程序入口点。
编译执行变化:
隐式
class生成规则优化支持包声明和模块指令
错误消息指向用户代码行而非生成代码
孵化器特性
向量API(第九次孵化)
JDK16引入了JEP 338: Vector API (Incubator)提供了jdk.incubator.vector来用于矢量计算 JDK17进行改进并作为第二轮的incubatorJEP 414: Vector API (Second Incubator) JDK18的JEP 417: Vector API (Third Incubator)进行改进并作为第三轮的incubator JDK19的JEP 426:Vector API (Fourth Incubator)作为第四轮的incubator JDK20的JEP 438: Vector API (Fifth Incubator)作为第五轮的incubator JDK21的JEP 448: Vector API (Sixth Incubator)作为第六轮的incubator JDK22的JEP 460: Vector API (th Incubator)作为第七轮的incubator JDK23的JEP 469: Vector API (Eighth Incubator)作为第八轮incubator JDK24则作为第九轮incubator,与JDK23相比做了一些变动:比如引入了一个新的基于值的类Float16,用于表示IEEE 754二进制16格式的16位浮点数。
SIMD编程模型:
硬件加速支持: 指令集支持操作加速比AVX-5128x双精度浮点并行6.8xNEON4x单精度浮点并行3.2xSVE可变长度向量操作4.5x
实验特性
分代Shenandoah垃圾回收器提升吞吐量与响应速度
JEP 404: Generational Shenandoah
该JEP主要是提供了一个实验性的分代模式,将分代概念引入Shenandoah GC,通过区分新生代和老年代实现了显著的性能突破。传统Shenandoah作为全堆回收器,每次GC都需要扫描整个堆空间,而分代版本通过以下机制优化:
新生代专用回收策略:采用复制算法快速回收短生命周期对象,减少老年代扫描频率
卡表(Card Table)优化:精确记录老年代到新生代的跨代引用,降低GC停顿时间30%以上
并行标记增强:在并发标记阶段优先处理新生代区域,使平均GC暂停时间控制在2ms以内 实测表明,在16GB堆内存的微服务场景下,分代Shenandoah相比原版吞吐量提升40%,同时保持亚毫秒级的最大暂停时间,成为低延迟应用的理想选择。
紧凑对象头设计减少内存占用
JEP 450: Compact Object Headers
重构了Java对象的内存布局,将 HotSpot JVM中的对象标头大小从96到128位减少到64位。Java程序中的对象往往很小,作为 Project Lilliput的一部分进行的实验表明,许多工作负载的平均对象大小为 256 到 512 位(32 到 64 字节)。这意味着超过 20% 的实时数据可以单独由对象标头获取。因此,即使对象标头大小略有改进,也可以显著减少占用空间、数据局部性并减轻 GC压力。在实际应用程序中试用过Project Lilliput的早期采用者证实,内存占用通常会减少10%–20%。关键技术突破包括:
压缩锁标志位:将原有的2字节Mark Word压缩为1字节,保留基本锁状态和hashcode信息
类型指针优化:使用32位偏移量替代64位类指针,配合压缩类空间(Compressed Class Space)工作
对齐填充智能分配:根据CPU缓存行特性动态调整对象填充策略 在包含百万级对象的电商应用中,该特性减少堆内存使用15%,同时由于更好的缓存局部性,使整体吞吐量提升8%。需要注意的是,该特性要求所有依赖JOL(Java Object Layout)工具的分析代码进行相应适配。