JDK 21 (LTS) 新特性概览:你需要知道的一切
Java 平台标准版(Java SE)21 于 2023 年 9 月正式发布,标志着 Java 发展史上的又一个重要里程碑。作为最新的长期支持版本(Long-Term Support,简称 LTS),JDK 21 将获得 Oracle 至少八年的免费安全更新和 Bug 修复支持(通常到 2031 年 9 月,Extended Support 可达更久)。这意味着 JDK 21 是一个高度稳定、功能丰富且适合企业级生产环境部署的版本。
距离上一个 LTS 版本 JDK 17 已过去两年,JDK 21 集成了期间发布的 JDK 18、19、20 中的大量创新特性,并将其中许多经过孵化和预览阶段的功能最终定型。本文将深入探讨 JDK 21 中的核心新特性,包括语言层面的改进、API 的增强以及 JVM 和性能方面的提升,带你全面了解这个 LTS 版本为何如此重要。
为什么选择 JDK 21 LTS?
选择 LTS 版本进行生产部署是业界普遍推荐的做法。LTS 版本意味着:
- 稳定性与成熟度: 特性经过多轮迭代和实际测试,API 相对稳定,Bug 较少。
- 长期支持: 获得官方长达数年的免费更新,无需频繁升级以获取安全补丁。
- 生态系统支持: 主流的框架、库和工具通常会优先且更好地支持 LTS 版本。
JDK 21 在前几个版本的探索性工作基础上,带来了几项“革命性”的特性,尤其是在并发和语言表达力方面,极大地提升了开发者的生产力和应用程序的性能与可伸缩性。
核心新特性概览 (按 JEP 编号排序,涵盖重要 JEPs)
JDK 21 中包含了 15 个主要的 JDK Enhancement Proposals (JEPs),其中 7 个是预览或孵化状态,8 个是最终定型的特性或移除的旧特性。下面我们将详细介绍其中最重要的部分。
1. 语言特性与语法糖 (提升开发者生产力)
JDK 21 在语言层面带来了显著的改进,使得代码更加简洁、易读且安全。
JEP 440: Record Patterns (Final)
Record Patterns(记录模式)首次在 JDK 19 中作为预览特性引入,并在 JDK 20 中进行了第二次预览,最终在 JDK 21 中正式定型。它与 Pattern Matching for instanceof
和 switch
结合使用,极大地简化了对记录类型(Records)的解构操作。
在 JDK 21 之前,如果你有一个嵌套结构的记录,例如:
java
record Point(int x, int y) {}
record Circle(Point center, int radius) {}
record Square(Point topLeft, int side) {}
你需要冗长地检查类型并手动访问字段:
java
Object obj = ...;
if (obj instanceof Circle c) {
Point center = c.center();
int radius = c.radius();
System.out.println("Circle at (" + center.x() + ", " + center.y() + ") with radius " + radius);
} else if (obj instanceof Square s) {
Point topLeft = s.topLeft();
int side = s.side();
System.out.println("Square at (" + topLeft.x() + ", " + topLeft.y() + ") with side " + side);
}
使用 Record Patterns,你可以直接在 instanceof
或 switch
语句中解构记录:
java
Object obj = ...;
if (obj instanceof Circle(Point center, int radius)) {
// center 和 radius 直接可用
System.out.println("Circle at (" + center.x() + ", " + center.y() + ") with radius " + radius);
} else if (obj instanceof Square(Point topLeft, int side)) {
// topLeft 和 side 直接可用
System.out.println("Square at (" + topLeft.x() + ", " + topLeft.y() + ") with side " + side);
}
更强大的地方在于模式的嵌套。你可以直接在 Record Patterns 中使用其他模式,包括 Record Patterns 本身:
java
Object obj = ...;
if (obj instanceof Circle(Point(int centerX, int centerY), int radius)) {
// centerX, centerY, radius 直接可用
System.out.println("Circle at (" + centerX + ", " + centerY + ") with radius " + radius);
}
这将嵌套结构的解构变得异常简洁,极大地提高了代码的可读性和编写效率,减少了 boilerplate code。
JEP 441: Pattern Matching for switch (Final)
Pattern Matching for switch
同样经过了多次预览,并在 JDK 21 中最终定型。它扩展了 switch
表达式和语句的功能,允许在 case
标签中使用模式(而不仅仅是常量),并提供更精确的类型匹配和条件判断。
在 JDK 21 之前,switch
只能用于基本类型、枚举、字符串或它们的包装类,并且 case
只能是常量。对于复杂的类型判断,通常需要使用 if-else if
链结合 instanceof
。
JDK 21 的 switch
允许在 case
中使用类型模式(Type Patterns):
java
Object obj = ...;
switch (obj) {
case String s -> System.out.println("It's a string: " + s.toUpperCase());
case Integer i -> System.out.println("It's an integer: " + i * i);
case null -> System.out.println("It's null"); // 处理 null
case Circle(Point center, int r) -> // Record Pattern 结合 switch
System.out.println("It's a circle with radius " + r);
case default -> System.out.println("It's something else");
}
主要改进包括:
- 类型模式匹配:
case Type var -> ...
形式,匹配成功后,变量var
可以直接在右侧的代码块中使用,且已经是正确的类型,无需强制转换。 - 处理
null
: 可以在case
标签中直接处理null
值,避免了额外的if (obj == null)
检查。 - 模式卫士 (Guarded Patterns): 可以在模式后面添加
when
子句来提供额外的条件判断,例如case String s when s.length() > 5 -> ...
。 - 穷举性检查 (Exhaustiveness): 编译器可以检查
switch
语句是否覆盖了所有可能的输入情况,特别是对于密封类(Sealed Classes),如果switch
覆盖了所有允许的子类型,可以省略default
子句。 - 作用域:
case
标签中定义的变量只在其对应的代码块(或者->
后面的表达式/语句)中有效。
Pattern Matching for switch
极大地提升了处理多类型分支逻辑时的代码清晰度和安全性。
JEP 443: Unnamed Patterns and Variables (Preview)
Unnamed Patterns and Variables(未命名模式和变量)在 JDK 21 中作为预览特性引入。其核心思想是允许开发者使用下划线 _
来表示一个不需要使用的变量或模式组件。这在某些场景下可以提高代码的可读性,明确表示“我收到了这个值/匹配了这个部分,但我不打算用它”。
使用场景示例:
- Catch 块中未使用的异常变量:
java
try {
// ... potentially throws IOException
} catch (IOException _) { // 明确表示不使用异常对象
System.err.println("An IOException occurred.");
// recovery logic not using the exception details
} - Lambda 表达式中未使用的参数:
java
// 假设一个方法需要两个参数,但你只需要第二个
BiConsumer<String, Integer> printer = (String _, Integer count) -> {
// String 参数被忽略
System.out.println("Count is: " + count);
}; - Record Patterns 中忽略部分组件:
java
record Point(int x, int y) {}
Object obj = new Point(10, 20);
if (obj instanceof Point(_, int y)) { // 只关心 y 坐标
System.out.println("Y coordinate is: " + y);
} - 传统的 For 循环中忽略迭代变量 (不常见,但语法允许):
java
List<Integer> numbers = List.of(1, 2, 3);
for (int _ : numbers) {
System.out.println("Just iterating..."); // 循环次数是关键,具体值不重要
}
注意,下划线 _
不仅仅是一个“占位符”,它是一种特殊的模式或变量声明,其行为与普通变量不同(例如,不能再次赋值给它)。这个特性旨在减少不必要的命名,使代码意图更清晰。
JEP 453: Unnamed Classes and Instance Main Methods (Preview)
这是 JDK 21 中引入的另一个重要预览特性,旨在简化 Java 程序的编写,特别是对于初学者或编写小型、单文件程序的情况。它取消了 Java 要求所有代码必须包含在类中的传统限制,并允许直接编写带有一个或多个方法(包括 main
方法)的代码块。
传统的 Java “Hello, World!” 需要:
java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
使用 Unnamed Classes 和 Instance Main Methods (在未来的版本中可能会演变为更通用的“隐式类”概念),你可以这样编写:
java
void main() { // 实例 main 方法
System.out.println("Hello, World!");
}
或者甚至:
java
System.out.println("Hello, World from implicitly declared class and main method!");
编译器会为这段代码自动创建一个不可见的类,并将 void main()
方法(如果存在)作为程序的入口点。如果不存在 main
方法,则顶层语句会作为程序入口。
这个特性:
- 降低入门门槛: 新手无需理解
public static void main(String[] args)
、类和静态的概念即可开始编写和运行简单的 Java 代码。 - 简化小型脚本: 对于编写简短的命令行工具或测试代码非常方便。
- 支持实例 Main 方法: 允许
main
方法访问同一文件中的非静态成员,使得代码更灵活。
这个特性尚处于预览阶段,其具体语法和语义在未来版本中可能会调整,但其方向是明确的:让 Java 在脚本和入门领域更具竞争力。
JEP 430: String Templates (Third Preview in JDK 21, now Final in JDK 22)
注意:虽然 String Templates 在 JDK 21 中是第三次预览,但它在 JDK 22 中才最终定型。不过,由于它在 JDK 21 中已经相对稳定且重要,许多用户会关注它。这里基于 JDK 21 的状态进行描述。
String Templates(字符串模板)同样经过多次预览。它提供了一种更直观、更安全的方式来组合字符串和变量值,避免了传统的字符串拼接(”+” 操作符)和 String.format()
方法的缺点。
传统方式:
java
String name = "Alice";
String greeting = "Hello, " + name + "!"; // 拼接
String greetingFormatted = String.format("Hello, %s!", name); // 格式化
使用 String Templates(在 JDK 21 语法中):
java
String name = "Alice";
String greeting = STR."Hello, \{name}!"; // STR 是一个内置的模板处理器
核心概念:
- 模板表达式: 由模板处理器(如
STR
)和一个包含嵌入表达式的模板体组成,嵌入表达式使用\{...}
语法。 - 模板处理器: 负责处理模板体和嵌入表达式的值,生成最终的字符串。JDK 21 提供了内置的
STR
处理器,用于简单的字符串插值。未来版本可能提供更多处理器(如FMT
用于格式化,RAW
用于原始文本)。 - 类型安全和可读性: 相比字符串拼接,模板表达式更清晰地表达了字符串的结构。相比
String.format
,它避免了格式说明符与变量列表不匹配的潜在错误。 - 安全性: 合理的模板处理器可以防止注入攻击(例如 SQL 注入),因为它们可以处理或验证嵌入的值,而不是简单地拼接。
虽然在 JDK 21 中只是预览,但 String Templates 已经是 Java 语言未来处理字符串的重要方向。
2. 并发与可伸缩性 (Java 迎来并发革命)
JDK 21 最令人兴奋且最具影响力的特性之一是 Project Loom 的成果,即虚拟线程的最终定型。
JEP 444: Virtual Threads (Final)
虚拟线程(Virtual Threads)是 JDK 21 中最重要的最终定型特性。它彻底改变了 Java 处理高并发 I/O 密集型应用的方式。
问题背景: 传统的 Java 线程(Platform Threads)是操作系统线程的简单包装。创建和管理 OS 线程开销很大,数量受限(通常几千个),阻塞(如等待 I/O)会导致 OS 线程挂起,浪费资源。这使得 Java 在处理大量并发连接(如 Web 服务器、微服务)时,采用“一个请求一个线程”的模型难以扩展,往往需要复杂的异步编程模型(如 CompletableFuture, Reactor, Vert.x)来提高吞吐量,但这增加了编程复杂性。
虚拟线程解决方案: 虚拟线程是一种由 JVM 管理的轻量级用户模式线程。它不像平台线程那样直接映射到 OS 线程。大量的虚拟线程可以“挂载”在少量的 OS 线程(称为“载体线程”,Carrier Threads)上运行。当虚拟线程遇到阻塞操作(如网络 I/O、Sleep),它会被 JVM “卸载”下来,释放其占用的载体线程去运行其他虚拟线程。当阻塞操作完成后,该虚拟线程会重新“挂载”到某个可用的载体线程上继续执行。
这意味着你可以创建数百万个甚至更多的虚拟线程,而不会耗尽 OS 资源。每个虚拟线程的创建开销非常小,几乎可以忽略不计。
带来的好处:
- 极大的可伸缩性: 可以轻松处理数万甚至数十万并发连接,而无需改变编程模型。
- 简化高并发编程: 开发者可以继续使用简单、直观的同步编程模型(类似传统的阻塞 IO 代码),但获得异步编程一样的可伸缩性。无需回调、Future 链或响应式流的复杂性。
- 提高资源利用率: 阻塞的虚拟线程不占用 OS 线程资源。
- 更好的可观察性: 线程 dump、调试器等工具对虚拟线程的支持使得调试高并发应用变得更容易。
如何使用:
创建虚拟线程非常简单,可以使用工厂方法:
“`java
// 最简单的创建方式
Thread.ofVirtual().start(() -> {
System.out.println(“Hello from virtual thread!”);
});
// 使用 ExecutorService 管理
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
System.out.println(“Running in a virtual thread pool”);
});
// 提交更多任务…
} // executor 关闭时会等待所有虚拟线程完成
“`
注意事项 (Pinning): 大多数情况下,虚拟线程遇到阻塞操作时会被卸载。但在某些特定场景下(如在 synchronized
代码块内部或调用 JNI 代码时),虚拟线程可能会被“钉死”(Pinning)在当前的载体线程上。这意味着即使遇到阻塞,载体线程也无法被释放,降低了虚拟线程的优点。应尽量避免在 synchronized
块内进行长时间的阻塞操作,优先使用 java.util.concurrent.locks.ReentrantLock
或其他非阻塞机制。
虚拟线程是 JDK 21 中最重要的生产力提升工具,将深刻影响 Java 应用的设计和架构。
JEP 446: Scoped Values (Preview)
Scoped Values(作用域值)是 Project Loom 的另一部分,旨在提供一种安全、高效的方式来在线程内部(包括虚拟线程)传递上下文数据,作为 ThreadLocal
的替代方案。它在 JDK 20 中首次作为孵化特性,在 JDK 21 中进入预览。
问题背景: ThreadLocal
允许在线程的整个生命周期中存储和访问线程本地的数据。但在虚拟线程场景下,ThreadLocal
存在效率问题(每个虚拟线程都有自己的 ThreadLocal
Map,即使不常用),且继承机制(InheritableThreadLocal
)与虚拟线程的调度模型不完全兼容,容易导致意外的数据共享或内存泄漏。此外,ThreadLocal
是可变的,可能导致线程之间的隐式依赖。
Scoped Values 解决方案: Scoped Values 提供了一种在特定作用域内传递不可变数据的方式。数据在父线程设置后,只会被子线程或在特定作用域内运行的代码访问。数据是不可变的,且只在创建其作用域的线程及其子孙线程(在作用域内创建的)的特定调用栈帧中可见。当作用域结束,数据自动清理。
使用方式:
“`java
// 1. 声明一个 ScopedValue
static final ScopedValue
// 2. 在特定作用域内绑定值并运行代码
void handleRequest(String id) {
ScopedValue.where(REQUEST_ID, id)
.run(() -> processRequest()); // processRequest 及其调用的方法可以访问 REQUEST_ID
}
// 3. 在作用域内的代码中读取值
void processRequest() {
String id = REQUEST_ID.get(); // 获取当前作用域内的值
System.out.println(“Processing request: ” + id);
// … 调用其他方法,它们也能访问 REQUEST_ID …
}
“`
Scoped Values 的优点:
- 效率: 数据只在需要时存储,并且与虚拟线程的调度模型高度兼容,性能优于
ThreadLocal
。 - 安全与不可变性: Scoped Values 的值是不可变的,防止了意外修改和隐式状态依赖。
- 清晰的作用域: 数据的生命周期由
where().run()
(或call()
) 方法明确界定。 - 与虚拟线程协同工作: 是在高并发、I/O 密集型应用中传递上下文(如请求 ID、安全上下文、事务信息)的理想选择。
JEP 453: Structured Concurrency (Preview)
Structured Concurrency(结构化并发)同样是 Project Loom 的一部分,并在 JDK 21 中进入预览。它提供了一种 API 来将一组相关的并发任务视为一个单一的工作单元。当这个工作单元完成或失败时,其所有子任务都会被相应地管理(例如,取消)。
问题背景: 在传统的并发编程中,启动多个子任务(例如,使用 ExecutorService
)后,管理它们的生命周期、错误处理和取消是复杂的。如果一个子任务失败,可能需要手动追踪并取消其他相关的子任务。
Structured Concurrency 解决方案: StructuredTaskScope
类允许创建并发任务的作用域。在这个作用域内启动的子任务,其生命周期与作用域绑定。
使用方式:
“`java
// 假设我们需要并发调用两个服务并合并结果,任何一个失败都应快速失败
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future
Future
scope.join() // 等待所有子任务完成 (或失败)
.throwIfFailed(); // 如果任何子任务失败,抛出异常
// 如果所有任务都成功,获取结果
String userData = user.resultNow();
int orderData = order.resultNow();
return process(userData, orderData);
} catch (Exception e) {
// 如果任何子任务失败,join().throwIfFailed() 会抛出异常
// 并且 scope 会自动尝试取消其他正在运行的子任务 (ShutdownOnFailure 策略)
handleError(e);
}
“`
StructuredTaskScope
的好处:
- 清晰的生命周期: 子任务的生命周期由其父任务或作用域管理,防止了“孤儿”线程。
- 改进的错误处理: 可以选择不同的关闭策略,如
ShutdownOnFailure
(任一子任务失败,立即取消其他子任务并关闭作用域)。 - 简化取消操作: 当作用域关闭或出错时,可以自动触发子任务的取消。
- 增强可观察性: 代码结构清晰地反映了任务之间的父子关系。
Structured Concurrency 结合虚拟线程,使得编写高并发、健壮且易于理解的服务变得更加可行。
3. 集合框架新 API
JEP 431: Sequenced Collections (New API)
JDK 21 引入了一组新的接口来表示具有确定顺序的集合:SequencedCollection
、SequencedSet
和 SequencedMap
。这个特性的目标是为那些拥有良好定义的首尾元素的集合提供统一的 API。
问题背景: 在 JDK 21 之前,Java 集合框架中存在一些集合类,它们内部维护着元素的特定顺序,并且支持访问或修改首尾元素(如 LinkedList
, Deque
, LinkedHashSet
, LinkedHashMap
)。然而,这些操作分散在不同的接口中(如 List
, Deque
),没有一个统一的父接口来表达“这是一个有确定顺序、并且可以方便访问或修改首尾元素的集合”。这导致代码难以对这类集合进行通用操作。
Sequenced Collections 解决方案:
SequencedCollection<E>
: 新的顶级接口,继承自Collection<E>
。提供了访问、添加和移除首尾元素的方法:getFirst()
,getLast()
addFirst(E)
,addLast(E)
removeFirst()
,removeLast()
reversed()
: 返回该集合的反向视图。
SequencedSet<E>
: 继承自SequencedCollection<E>
和Set<E>
。SequencedMap<K, V>
: 新的接口,继承自Map<K, V>
。提供了访问、添加和移除首尾 entry 的方法,以及反向视图:firstEntry()
,lastEntry()
putFirst(K, V)
,putLast(K, V)
removeFirst()
,removeLast()
reversed()
: 返回该 Map 的反向视图。
影响:
- 现有的集合类如
LinkedList
,ArrayList
,Deque
,LinkedHashSet
,LinkedHashMap
都被修改以实现这些新的接口。 - 开发者现在可以编写针对
SequencedCollection
或SequencedMap
接口的通用代码,而不用关心具体的实现类是LinkedList
还是ArrayList
(如果是顺序访问)。 reversed()
方法提供了一种高效的方式来获取集合或 Map 的反向视图,而无需创建新的集合对象。
这个 API 改进使得处理顺序敏感的集合变得更加统一和便捷。
4. JVM、垃圾回收与性能
JDK 21 在 JVM 和垃圾回收方面也带来了一些重要的增强。
JEP 439: Generational ZGC (Preview)
Z Garbage Collector (ZGC) 是一个设计用于实现极低暂停时间(亚毫秒级)的并发垃圾回收器。Generational ZGC(分代 ZGC)在 JDK 21 中作为预览特性引入。
问题背景: 大多数对象的生命周期都很短(“朝生暮死”)。非分代垃圾回收器需要扫描整个堆来查找和回收垃圾,即使是许多新生对象很快就会变成垃圾。分代垃圾回收器将堆分为“年轻代”和“老年代”,专注于更频繁地收集年轻代,这通常能显著减少 GC 暂停时间并提高吞吐量。之前的 ZGC 版本是非分代的。
Generational ZGC 解决方案: 将 ZGC 扩展为支持分代回收。它仍然保留了 ZGC 原有的低暂停时间和高吞吐量特性,并在此基础上通过分代优化,进一步减少了需要扫描的对象数量,降低了 CPU 使用率和 GC 引起的延迟。
这个特性对于那些已经在使用 ZGC 或考虑使用 ZGC 的应用来说,是一个重要的性能改进选项。
JEP 454: Generational Shenandoah (Preview)
与 Generational ZGC 类似,Generational Shenandoah 将分代概念引入了 Shenandoah GC。Shenandoah 是另一个低暂停时间的并发垃圾回收器,最初由 Red Hat 开发。
问题背景: Shenandoah 在处理大堆时的暂停时间非常稳定和短暂。将其分代化可以利用对象生命周期的特性,进一步提高垃圾回收效率和整体性能。
Generational Shenandoah 解决方案: 将 Shenandoah 扩展为分代收集器。这使得 Shenandoah 也能享受到分代回收带来的性能优势,例如更小的年轻代收集暂停和更高的吞吐量,特别是对于那些产生大量短命对象的应用。
Generational Shenandoah 为开发者提供了另一个强大的低暂停时间分代 GC 选项。
JEP 448: GCMC-Based Cryptography (New API)
这个 JEP 引入了一个新的 API 来支持使用 Galois/Counter Mode (GCM) 和 Counter with CBC-MAC (CCM) 进行加密操作。这两种模式是常用的认证加密模式,在保证数据隐私的同时,还能验证数据的完整性和真实性。
这个特性主要面向需要进行安全数据处理和传输的应用,提供了标准的、高效的 API 支持。
JEP 452: Key Encapsulation Mechanism API (New API)
Key Encapsulation Mechanism (KEM) 是一种加密技术,用于安全地生成和交换对称密钥。与传统的密钥交换算法(如 Diffie-Hellman)不同,KEM 关注的是如何将一个对称密钥安全地“封装”给接收方。这在混合加密方案(使用非对称加密传输对称密钥)中非常有用,尤其是在考虑后量子密码学时。
这个 API 提供了对 KEM 算法的抽象支持,使得开发者可以在 Java 中方便地使用这些机制来增强应用的安全性,特别是在面向未来加密算法演进时。
5. 预览与孵化中的其他重要特性
除了上面详细介绍的特性,JDK 21 还继续孵化或预览了一些将在未来版本中最终定型的特性:
- JEP 442: Foreign Function & Memory API (Third Preview):旨在提供一种安全、高效的方式,让 Java 程序能够方便地调用本地代码(例如 C/C++ 库)并访问本地内存。这是 JNI 的现代替代方案,克服了 JNI 的复杂性、风险和性能限制。
- JEP 443: Unnamed Patterns and Variables (Preview):前面已详细介绍。
- JEP 446: Scoped Values (Preview):前面已详细介绍。
- JEP 453: Structured Concurrency (Preview):前面已详细介绍。
- JEP 454: Generational Shenandoah (Preview):前面已详细介绍。
- JEP 455: Preview Feature Naming Convention (Miscellaneous):这是一个内部 JEP,规范了预览特性的命名方式。
此外,还有 JEP 432 Vector API (Fifth Incubator) 和 JEP 448 Vector API (Sixth Incubator),Vector API 旨在利用 SIMD (Single Instruction, Multiple Data) 指令来加速向量计算,这对于科学计算、机器学习等领域非常重要。它仍在孵化阶段,表明 API 设计仍在探索和完善中。
6. 废弃与移除
作为 LTS 版本,JDK 21 也进行了一些清理工作,废弃或移除了不再推荐或过时的 API 和功能:
- JEP 449: Deprecate the Windows 32-bit x86 Port for Removal: Windows 32 位 x86 移植版被废弃,并计划在未来版本中移除。这意味着 Java 将逐步停止对这个平台的官方支持。
- JEP 448: Prepare to Disallow the Dynamic Loading of Agents: 准备在未来版本中默认禁止通过命令行在运行中的 JVM 上动态加载代理 (Agents),以增强安全性。这可能会影响一些工具,但提供了新的、更安全的加载代理的方式。
- 继续废弃或移除其他一些旧的或不安全的 API,例如一些内部的
SocketImpl
实现等。
在升级到 JDK 21 时,检查应用是否使用了任何废弃或移除的 API 是一个重要的步骤。
总结:JDK 21 的意义
JDK 21 是一个极具里程碑意义的 LTS 版本。它不仅仅是前几个非 LTS 版本的简单叠加,更是将 Project Loom (虚拟线程、Scoped Values、Structured Concurrency) 等改变 Java 并发模式的重量级特性推向了生产可用状态。同时,语言层面的改进 (Pattern Matching for switch, Record Patterns, Unnamed Patterns/Variables, String Templates 预览) 极大地提高了开发者的生产力,使得 Java 代码更加现代化和表达力强。JVM 和 GC 的增强,特别是分代 ZGC 和分代 Shenandoah 的预览,预示着未来 Java 在性能和内存管理上的持续优化。
对于企业和开发者而言,升级到 JDK 21 是一个非常值得考虑的选择。虚拟线程的到来将简化许多高并发应用的开发和维护,模式匹配的增强将使代码更简洁易读。作为一个 LTS 版本,它提供了长期的稳定支持,是当前 Java 生态系统中最推荐的生产环境目标版本。
当然,对于预览特性(如 Scoped Values, Structured Concurrency, Unnamed Features),虽然功能强大且令人期待,但在生产环境中使用时仍需谨慎,密切关注其后续版本的变化和最终定型状态。
总而言之,JDK 21 巩固了 Java 作为现代、高性能、高可伸缩性平台™的地位,为迎接新的挑战(如大规模微服务、云原生应用、AI/ML 工作负载)做好了准备。现在是时候开始探索和拥抱 JDK 21 的强大功能了!