Java中各个LTS版本新特性梳理
Java中各个LTS版本新特性梳理
一、Java8新特性梳理
1. Lambda 表达式
Lambda 表达式是 Java 8 最引人注目的特性,它允许你将功能作为方法参数,或者将代码本身当作数据。它提供了一种清晰且简洁的方式来表示一个方法接口(通常是函数式接口)的实例。
语法:(parameters) -> expression
或(parameters) -> { statements; }
示例:
1 | // 1. 无参数,无返回值 |
2. 函数式接口
函数式接口是只有一个抽象方法的接口。它可以用作 Lambda 表达式的类型。Java 8 提供了 @FunctionalInterface 注解来显式标识一个接口是函数式接口。
常见的函数式接口:
Runnable->run()Callable<V>->call()Comparator<T>->compare(T o1, T o2)- **
Consumer<T>**: 消费一个参数,无返回值(T t) -> void - **
Supplier<T>**: 不取参数,返回一个值() -> T - **
Function<T, R>**: 接受一个参数,返回一个结果(T t) -> R - **
Predicate<T>**: 接受一个参数,返回布尔值(T t) -> boolean
示例:
1 | // 自定义函数式接口 |
3. 方法引用与构造器引用
方法引用提供了一种更简洁的 Lambda 表达式,用于直接指向已有方法。它们是 Lambda 的语法糖。
语法:
object::instanceMethod->System.out::printlnClass::staticMethod->Math::maxClass::instanceMethod->String::length(第一个参数成为方法的目标)Class::new(构造器引用) ->ArrayList::new
示例:
1 | import java.util.Arrays; |
4. Stream API
java.util.stream.Stream 是 Java 8 处理集合(Collection)的关键抽象概念。它可以对集合进行非常复杂的查找、过滤、映射数据等操作。Stream 操作分为中间操作(返回 Stream)和终端操作(返回具体结果或副作用)。
特点:
- 不是数据结构:它不存储数据,而是通过管道从源(如集合、数组)获取数据。
- 函数式编程:对流的操作会产生结果,但不会修改源数据。
- 惰性执行:中间操作总是惰性的,终端操作是触发实际计算的触发器。
- 可消费性:Stream 只能被消费一次。
操作类型:
- 中间操作:
filter,map,flatMap,distinct,sorted,peek,limit,skip - 终端操作:
forEach,collect,count,anyMatch,allMatch,noneMatch,findFirst,findAny,reduce,min,max
示例:
1 | import java.util.*; |
5. Optional 类
java.util.Optional<T> 是一个容器对象,可能包含也可能不包含非 null 值。它旨在避免显式的 null 检查,从而减少 NullPointerException。
示例:
1 | import java.util.Optional; |
6. 新的日期时间 API (java.time)
Java 8 引入了全新的日期时间 API (java.time 包) 来修正旧 Date 和 Calendar 类的诸多问题。它是基于 Joda-Time 库设计的,并且是不可变的和线程安全的。
核心类:
LocalDate: 只包含日期,例如2023-10-27LocalTime: 只包含时间,例如15:30:00LocalDateTime: 包含日期和时间ZonedDateTime: 包含时区的日期时间Instant: 时间戳(Unix 时间)Duration: 时间段,基于时间(秒,纳秒)Period: 时间段,基于日期(年,月,日)DateTimeFormatter: 格式化和解析日期时间
示例:
1 | import java.time.*; |
7. 接口的默认方法和静态方法
Java 8 允许在接口中添加默认方法(使用 default 关键字)和静态方法。
- 默认方法: 允许向现有接口添加新功能,同时确保与为这些接口的旧版本编写的代码的二进制兼容性。它提供了默认实现。
- 静态方法: 允许在接口中定义静态工具方法,可以通过接口名直接调用。
示例:
1 | public interface Vehicle { |
8. Nashorn JavaScript 引擎
Java 8 引入了新的 JavaScript 引擎 Nashorn,取代了旧的 Rhino 引擎。它提供了更好的性能,并允许在 JVM 上直接运行 JavaScript 代码。
示例 (在 Java 代码中执行 JS):
1 | import javax.script.*; |
注意:从 Java 11 开始,Nashorn 已被标记为废弃,并在后续版本中移除。
总结表格
| 特性 | 描述 | 主要优点 |
|---|---|---|
| Lambda 表达式 | 简洁的匿名函数表示法 | 代码更简洁,便于函数式编程 |
| 函数式接口 | 只有一个抽象方法的接口 | Lambda 表达式的类型基础 |
| 方法引用 | 更简洁地指向已有方法 | 进一步简化 Lambda 表达式 |
| Stream API | 对数据源进行函数式操作 | 强大的集合处理能力,并行支持 |
Optional |
容器类,可能包含也可能不包含值 | 避免 NullPointerException |
| 新的日期时间 API | java.time 包下的新类 |
清晰、不可变、线程安全 |
| 接口默认/静态方法 | 接口中可以包含实现的方法 | 增强接口能力,保持向后兼容 |
| Nashorn JavaScript | 新的 JS 引擎 | 更好的 JS 执行性能 (已在 JDK 11+ 移除) |
二、Java11新特性梳理
Java 11 作为继 Java 8 之后的第二个长期支持(LTS)版本,于2018年9月发布。它带来了不少便利的特性、性能提升和改进。我来为你梳理一下 Java 11 的主要新特性,并提供相应的代码示例。
🧪 1. 局部变量类型推断增强(Lambda 参数支持 var)
Java 10 引入了局部变量类型推断 (var),Java 11 将其扩展到了 Lambda 表达式的参数中。这使得你可以在 Lambda 参数中使用 var 声明,并且可以附加注解(例如 @Nullable)。
1 | import java.util.List; |
说明:
- 这并非为了省略类型(Lambda 中类型本身可省略),而是为了能够在参数上添加注解(如
@Nullable,@Nonnull)来提供更强的类型检查约束。 - 使用
var时,所有参数都必须使用var,不能部分使用var部分显式声明类型。
🔤 2. 字符串增强方法
Java 11 为 String 类新增了几个非常实用的方法,用于简化常见的字符串操作。
1 | public class StringMethods { |
🌐 3. 标准 HTTP 客户端 API
Java 11 将 Java 9 中引入并在 Java 10 中更新的孵化器 HTTP 客户端 API (jdk.incubator.http) 进行了标准化,并将其纳入 java.net.http 包。这个新的客户端支持 HTTP/1.1 和 HTTP/2,以及 WebSocket,提供了同步和异步两种调用方式。
1 | import java.net.URI; |
📁 4. 单文件源代码程序直接运行
Java 11 允许你直接运行单个 .java 文件,而无需先使用 javac 显式编译。这对于快速测试小脚本或教学示例非常方便。
HelloWorld.java:
1 | public class HelloWorld { |
在命令行中直接运行:
1 | java HelloWorld.java |
输出:
1 | Hello,直接运行单文件源码! |
说明:
- Java 虚拟机会在内存中编译并执行该源文件。
- 这个功能不适用于有多个类定义或依赖复杂的大型项目。
🗑️ 5. Epsilon:低开销垃圾收集器 (“No-Op”)
Java 11 引入了一个实验性的无操作 (No-Op) 垃圾收集器 —— Epsilon GC。它只负责内存分配,不进行任何垃圾回收。当堆内存耗尽时,JVM 会关闭。
应用场景:
- 性能测试:用于对比其他 GC 的开销,排除 GC 活动对性能测试结果的干扰。
- 超短生命周期任务:任务运行时间极短,在堆内存耗尽前就会结束,无需垃圾回收。
- VM 接口测试或极端延迟优化(由开发者完全控制内存生命周期)。
使用方式(需添加 JVM 参数):
1 | java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xmx1g MyApplication |
✈️ 6. Flight Recorder 集成
Java Flight Recorder (JFR) 之前是 Oracle JDK 中的商业功能,在 Java 11 中集成到了 OpenJDK,并且可以免费使用。JFR 是一个高性能的性能分析和诊断工具,可用于收集 JVM 和应用程序运行时的详细数据,而对性能的影响很小。
启动 JFR 录制(可以在应用启动时或运行时通过 jcmd 触发):
1 | java -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr,settings=profile MyApplication |
说明:
- 录制的数据文件 (
myrecording.jfr) 可以使用 JDK Mission Control (JMC) 工具进行分析,可视化地查看 CPU 使用、内存分配、锁竞争、I/O 等信息。
🔒 7. 嵌套基于访问控制(Nest-Based Access Control)
这是一个 JVM 级别的改进,旨在简化嵌套类(如内部类)之间对私有成员的访问,并减少编译器生成的合成桥接方法(synthetic bridge methods)。
示例:
在 Java 11 之前,下面的代码可能会由编译器生成一些额外的“桥接”方法来让 Inner 访问 Outer 的私有字段。Java 11 引入了 nests 的概念,使这种访问更加直接自然。
1 | public class Outer { |
说明:
- 这主要是一个底层改进,通常不需要修改你的代码,但可以使生成的字节码更简洁,并可能带来微小的性能提升。
🔐 8. TLS 1.3 支持
Java 11 支持 TLS 1.3 协议,这是一个更安全、性能也更优的新版本传输层安全协议。
1 | import javax.net.ssl.SSLContext; |
TLS 1.3 的优点:
- 更强的安全性:移除了一些不安全的加密算法,简化了握手过程以减少攻击面。
- 更快的连接速度:握手过程所需的往返次数 (Round-Trip Time, RTT) 减少,连接建立更快。
📊 9. 集合 API 增强
Java 11 为集合接口(List, Set, Map)添加了一些便利的工厂方法,用于创建不可变的集合。
1 | import java.util.List; |
说明:
- 这些方法 (
List.of,Set.of,Map.of) 创建的是不可变集合,任何尝试修改的操作都会导致UnsupportedOperationException。 - 它们为快速创建小型集合提供了便利,替代了传统的
Arrays.asList或手动构建的方式。
📝 10. 其他值得注意的变更
- 移除和废弃的模块:
- 移除了 Java EE (如
javax.xml.ws) 和 CORBA 模块。如果你需要这些功能,需要手动添加相关的依赖(例如 JAX-WS RI)。 - 废弃了 Nashorn JavaScript 引擎 (考虑迁移到 GraalVM 的 JavaScript 实现)。
- 移除了 JavaFX,它已成为一个独立的项目。
- 移除了 Java EE (如
- Unicode 10 支持:更新支持 Unicode 10.0 标准,新增了字符和符号。
Files类新增读写字符串方法:方便地进行小文本文件的读写。1
2
3
4
5import java.nio.file.*;
Path path = Files.writeString(Path.of("test.txt"), "Hello Java 11!");
String content = Files.readString(path);
System.out.println(content); // Hello Java 11!
💎 总结与建议
Java 11 作为长期支持版本,不仅提供了语言特性和 API 的增强(如 HTTP 客户端、字符串方法、局部变量推断增强),还在性能(如 ZGC、JFR)、安全性(TLS 1.3)和开发体验(单文件运行)方面带来了重要改进。
下面的表格帮你快速回顾 Java 11 的主要新特性:
| 特性类别 | 核心特性 | 说明与收益 |
|---|---|---|
| 语言语法 | Lambda 参数使用 var |
支持在 Lambda 参数上添加注解 |
新增字符串方法 (isBlank, lines, repeat, strip) |
简化字符串操作,支持 Unicode 空白字符 | |
| API 增强 | 标准 HTTP 客户端 | 支持 HTTP/2, 同步/异步调用,取代 HttpURLConnection |
集合工厂方法 (List.of, Set.of, Map.of) |
快速创建不可变集合 | |
| 工具与JVM | 单文件源码直接运行 | 无需 javac 编译,直接 java HelloWorld.java |
| Epsilon 垃圾收集器 | 实验性 No-Op GC,用于性能测试等特殊场景 | |
| Flight Recorder (JFR) 集成 | 高性能性能监控工具,集成到 OpenJDK | |
| 嵌套基于访问控制 | JVM 底层优化,简化嵌套类私有访问 | |
| 安全性与其他 | TLS 1.3 支持 | 更安全、更快的安全协议 |
| 移除 Java EE & CORBA 模块 | JDK 更轻量,需手动添加依赖 |
三、Java17新特性梳理
🧬 1. 密封类 (Sealed Classes)
密封类(接口)允许你明确规定哪些其他类或接口可以扩展或实现它。这提供了对继承层次结构的更强控制,有助于建模固定的领域,并增强代码的安全性。
1 | // 定义一个密封类 Shape,只允许 Circle 和 Rectangle 继承 |
说明:
- 使用
sealed关键字修饰类或接口。 - 使用
permits关键字指定允许继承的子类。 - 子类必须是
final,sealed或non-sealed之一。 - 密封类通常与模式匹配(如
instanceof和switch)结合使用,编译器可以检查是否覆盖了所有允许的子类。
🔍 2. 模式匹配 (Pattern Matching)
模式匹配简化了对象类型检查和转换的代码编写,使代码更简洁、安全。
instanceof 模式匹配
在 Java 17 中,instanceof 可以直接将匹配的对象转换为目标类型并赋值给一个变量。
1 | public class PatternMatchingExample { |
Switch 表达式模式匹配(预览功能)
虽然在 Java 17 中 Switch 表达式模式匹配仍为预览功能,但值得了解。
1 | public class SwitchPatternMatching { |
注意:要使用预览功能,编译和运行时需添加 --enable-preview 参数。
📝 3. 文本块 (Text Blocks)
文本块简化了多行字符串(如 JSON、HTML、SQL)的编写,无需大量的转义和连接操作。
1 | public class TextBlocksExample { |
说明:
- 文本块以
"""开始,以"""结束。 - 编译器会自动处理缩进和换行。
- 可以使用
formatted方法进行格式化,类似于String.format()。
🧱 4. 不可变集合工厂方法
Java 17 提供了更简便的方法来创建不可变的集合(List, Set, Map)。
1 | import java.util.List; |
说明:
- 这些工厂方法创建的是不可修改的集合,任何修改操作都会导致
UnsupportedOperationException。 - 它们为创建小型集合提供了便利,并且通常比可变集合更节省内存。
🔐 5. 强封装 JDK 内部 API
Java 17 默认强封装了所有 JDK 的内部 API(如 sun.misc 包中的类)。这意味着除非显式打开包,否则无法通过反射等方式访问这些内部 API。这提高了安全性,鼓励开发者使用标准、公开的 API。
1 | import sun.misc.Unsafe; // 在 Java 17 中,这会导致编译错误 |
应对策略:
- 寻找并替换为公开的、标准的 API(例如,对于
Unsafe的部分功能,可以考虑使用VarHandle)。 - 如果必须使用(例如某些第三方库暂时尚未更新),在启动 JVM 时可以使用
--add-opens命令行参数来显式打开特定的模块和包,但这仅应作为临时手段。
⚙️ 6. 垃圾收集器改进
Java 17 在垃圾收集器方面持续改进,特别是 ZGC 和 Shenandoah,它们的目标都是尽可能减少垃圾收集的停顿时间,适用于大内存和低延迟要求的应用场景。
- ZGC (Z Garbage Collector): 一种可扩展的低延迟垃圾收集器。
- Shenandoah: 一种低停顿时间的垃圾收集器。
使用方式(通过 JVM 启动参数启用):
1 | # 启用 ZGC |
说明:
- 这些 GC 适用于需要低延迟(停顿时间短)的应用,如游戏服务器、金融交易系统等。
- 选择合适的 GC 需要根据应用的具体特点(内存分配模式、吞吐量要求等)进行测试和调优。
📦 7. jpackage 工具
jpackage 工具允许你将 Java 应用程序打包为特定于平台的本地格式,如 Windows 上的 .msi 或 .exe,macOS 上的 .dmg 或 .pkg,以及 Linux 上的 .deb 或 .rpm。这极大地简化了 Java 应用的分发和安装。
基本用法:
假设你有一个打包好的 JAR 应用 myapp.jar 和主类 com.example.Main。
1 | jpackage --name MyApplication \ |
说明:
jpackage会创建一个包含** Java 运行时环境(JRE)** 的安装包,用户无需预先安装 Java。- 这使得 Java 应用的分发体验更接近原生应用。
💎 总结与建议
Java 17 作为长期支持版本,不仅提供了许多现代语言特性(如密封类、模式匹配),增强了代码的表达能力和安全性,还在性能(GC)、安全性(强封装内部 API)和分发体验(jpackage)方面带来了重要改进。
下面是一个表格,汇总了 Java 17 的主要新特性:
| 特性类别 | 核心特性 | 说明 |
|---|---|---|
| 语言语法 | 密封类 (Sealed Classes) | 限制类的继承,提高代码安全性和可维护性 |
| instanceof 模式匹配 (Pattern Matching for instanceof) | 简化 instanceof 检查和类型转换 |
|
| 文本块 (Text Blocks) | 简化多行字符串的编写,支持格式化 | |
| API 增强 | 不可变集合工厂方法 | 更方便地创建不可变集合 (List.of, Set.of, Map.of) |
| JVM 与性能 | 强封装 JDK 内部 API | 默认禁止反射访问内部 API,提升安全性 |
| 垃圾收集器改进 (ZGC, Shenandoah) | 降低垃圾收集暂停时间,提升吞吐量 | |
| 工具与其他 | jpackage 工具 |
将 Java 应用程序打包为本地安装包 |
升级建议:
- 对于新项目,强烈建议直接从 Java 17 开始,以利用其所有现代特性和长期支持。
- 对于现有项目,升级到 Java 17 前需要:
- 仔细测试,确保第三方库和框架与 Java 17 兼容。
- 检查代码是否依赖了 JDK 内部 API,并进行重构。
- 评估新特性(如密封类、模式匹配)是否能为现有代码带来好处。
四、Java21新特性梳理
Java 21 作为最新的长期支持(LTS)版本,带来了一系列令人兴奋的新特性,旨在提升开发效率、代码可读性、并发性能以及整体应用运行效率。下面我将为你梳理其主要新特性,并提供相应的示例代码。
下面表格汇总了 Java 21 的主要新特性:
| 特性类别 | 核心特性 | 简要说明 |
|---|---|---|
| 并发编程 | 虚拟线程 (Virtual Threads) - JEP 444 | 轻量级线程,由 JVM 管理,大幅提升高并发应用的性能和可扩展性 |
| 结构化并发 (Structured Concurrency) - JEP 453 | 简化并发编程,将多个子任务视为一个工作单元,提升可靠性和可观察性 | |
| 语言语法与特性 | 记录模式 (Record Patterns) - JEP 440 | 在模式匹配中解构记录(Record)对象,简化数据访问 |
| 字符串模板 (String Templates) - 预览功能 JEP 430 | 简化字符串拼接,支持嵌入式表达式 | |
| 未命名模式和变量 (Unnamed Patterns & Variables) | 使用 _ 忽略不需要的模式或变量,减少冗余代码 |
|
| API 增强 | 序列化集合 (Sequenced Collections) | 为集合框架引入了新的接口和方法,以便更直观地访问首尾元素 |
| JVM 与性能 | 分代式 ZGC (Generational ZGC) - JEP 439 | ZGC 垃圾收集器引入分代机制,进一步提升垃圾回收效率,减少停顿时间 |
| 记录模式 (Record Patterns) - JEP 440 | 在模式匹配中解构记录(Record)对象,简化数据访问 |
接下来,我们详细看看这些新特性。
🧵 1. 虚拟线程 (Virtual Threads) - JEP 444
虚拟线程是 Java 21 中最具革命性的特性之一,旨在从根本上简化高并发应用的开发,并提升其可扩展性。它是一种由 JVM 管理的轻量级线程,创建和切换开销极低,因此可以轻松创建数百万个虚拟线程,而不会像传统平台线程那样耗尽资源。
传统线程模型的局限性:
在 Java 21 之前,Java 使用的是平台线程(Platform Threads)模型,每个 Java 线程都直接映射到一个操作系统线程。这种模型下,线程的创建成本高、数量受限且上下文切换开销大,使得传统 Java 应用在高并发场景下容易遇到瓶颈。
虚拟线程的优势:
- 内存占用极低:每个虚拟线程初始仅需几百字节内存。
- 创建数量几乎无限制:可轻松创建数百万个虚拟线程。
- 由 JVM 调度:不绑定特定操作系统线程,切换开销极小。
创建虚拟线程的几种方式:
1 | // 1. 使用静态方法 Thread.startVirtualThread |
性能对比(根据提供的测试数据):
| 指标 | 传统线程池 (200线程) | 虚拟线程 (10000并发) | 提升幅度 |
|---|---|---|---|
| 吞吐量 (requests/s) | 3,200 | 12,800 | 300% |
| 平均延迟 (ms) | 62 | 15 | 75%降低 |
| 内存占用 (MB) | 210 | 45 | 78%降低 |
最佳实践与注意事项:
- 适合I/O密集型任务:虚拟线程在等待I/O操作(如网络请求、数据库查询)时能够高效释放底层载体线程,非常适合处理大量并发I/O操作。
- 计算密集型任务需谨慎:对于计算密集型任务(CPU-bound),虚拟线程的优势不明显,因为大量计算本身就会占用载体线程。
- 避免同步阻塞操作:在虚拟线程内执行同步阻塞I/O操作(如传统的
java.net.Socket)会浪费其优势,应使用异步NIO API。 - **谨慎使用
ThreadLocal**:由于虚拟线程数量可能极大,滥用ThreadLocal可能导致内存消耗增加。
🧩 2. 记录模式 (Record Patterns) - JEP 440
记录模式允许你在 instanceof 检查和 switch 表达式中直接解构(Destructure)记录(Record)对象,简洁地提取其组件,使代码更加清晰和安全。
示例:不使用记录模式 vs 使用记录模式
1 | // 定义一个记录(Record) |
📝 3. 字符串模板 (String Templates) - 预览功能 JEP 430
字符串模板是一种表达式插值特性,允许你将表达式直接嵌入字符串字面量中,使字符串拼接更加直观和安全(避免注入风险)。该特性在 Java 21 中为预览功能。
示例:传统拼接 vs 字符串模板
1 | String name = "Alice"; |
🧭 4. 结构化并发 (Structured Concurrency) - JEP 453
结构化并发旨在简化并发编程,它将多个同时运行的任务(例如通过 fork)视为一个工作单元(通过 StructuredTaskScope)。这样,错误传播和取消变得更加可靠,任务的生命周期也更容易管理,从而避免了线程泄漏和取消延迟等问题。
核心思想:
- 任务层次结构:子任务的生命周期严格嵌套在父任务中。
- 错误传播:任何子任务失败会取消所有同级任务并向父任务传播异常。
- 资源管理:使用
try-with-resources确保所有线程在作用域结束时完成。
示例:聚合多个微服务响应
1 | import java.util.concurrent.*; |
在这个例子中,如果 findUser 或 fetchOrder 中的任何一个失败,另一个任务会被自动取消。StructuredTaskScope 提供了两种策略:ShutdownOnFailure(任一失败则取消所有)和 ShutdownOnSuccess(任一成功则取消所有)。
🗑️ 5. 分代式 ZGC (Generational ZGC) - JEP 439
ZGC 是一款低延迟的垃圾收集器。Java 21 为其引入了分代机制(Generational ZGC),即区分年轻代(Young Generation)和老年代(Old Generation)。大部分对象都是“朝生夕死”的,分代后,ZGC 可以更频繁、更快速地收集年轻代,从而减少 Full GC 的次数,进一步降低垃圾收集的停顿时间,提升应用程序的吞吐量。
启用方式:
1 | # 启用分代式 ZGC (Java 21+) |
🧰 6. 序列化集合 (Sequenced Collections)
Java 21 为集合框架引入了一组新的接口,用于表示具有明确遍历顺序的集合,并提供了更方便的方法来访问其第一个和最后一个元素。
新增的核心接口:
SequencedCollection<E>: 定义了具有序列的集合(如LinkedList,LinkedHashSet)。SequencedSet<E>: 不允许重复元素的SequencedCollection(如LinkedHashSet)。SequencedMap<K,V>: 定义了具有序列的映射(如LinkedHashMap)。
新方法示例:
1 | // SequencedCollection / SequencedSet |
🎭 7. 未命名模式和变量 (Unnamed Patterns & Variables) - JEP 443
该特性允许你使用下划线 _ 来表示未命名的模式或变量。当你需要声明一个变量但又不需要使用它时(例如在 catch 块、try-with-resources 或模式匹配中),这可以减少冗余代码,提高可读性。
示例:
1 | // 未命名变量示例 |
💡 其他值得注意的改进
- 未命名类和实例 main 方法 (JEP 445 - 预览): 简化了入门程序,允许省略类声明和
main方法的传统参数。1
2
3
4
5
6
7
8// 传统的 main 方法
void main(String[] args) {
System.out.println("Hello, World!");
}
// 更简化的形式(预览)
void main() {
System.out.println("Hello, Simplified World!");
} - 密钥封装机制 API (KEM - JEP 461): 提供了使用公钥密码加密对称密钥的标准 API。
- 弃用和移除:
- 出于安全考虑,弃用了 Windows 32 位 x86 端口。
- 移除了
IdentityHashMap和StringBuffer中的过时构造方法。
🚀 如何开始使用 Java 21 新特性
- 启用预览特性:字符串模板、未命名类和实例 main 方法等是预览功能。编译和运行时需添加参数:(在 IDE 中通常也有相应配置选项)
1
2javac --release 21 --enable-preview MyClass.java
java --enable-preview MyClass - 谨慎评估:对于生产环境,特别是 LTS 版本,建议充分测试新特性(尤其是预览功能)的稳定性和兼容性。
五、Java25新特性梳理
先通过一个表格快速了解 Java 25 的主要新特性:
| 特性类别 | 核心特性 | 状态 | 对开发的主要价值 |
|---|---|---|---|
| 语言与语法 | JEP 507: 原始类型模式匹配 | 第三预览版 | 简化基本类型的类型检查和提取,代码更简洁 |
| JEP 511: 模块导入声明 | 正式 | 简化模块依赖声明,减少重复的 import 语句 |
|
| JEP 512: 紧凑源文件和实例 main 方法 | 正式 | 降低学习门槛,简化简单程序的编写 | |
| JEP 513: 灵活的构造函数体 | 正式 | 允许在构造函数中先进行参数验证再调用 super(),更安全 |
|
| API 增强 | JEP 506: 作用域值 (Scoped Values) | 正式 | 轻量级且不可变的线程内数据共享,优于 ThreadLocal |
| JEP 505: 结构化并发 (Structured Concurrency) | 第五预览版 | 简化多线程任务管理,提高可靠性和可观测性 | |
| JEP 508: Vector API | 第十次孵化 | 表达向量计算,可靠编译为优化向量指令,提升计算性能 | |
| 安全增强 | JEP 470: 加密对象的 PEM 编码 | 预览 | 简化加密对象(密钥、证书)与 PEM 格式间的转换 |
| JEP 510: 密钥派生函数 API | 正式 | 支持多种算法,为量子安全加密过渡做准备 | |
| 性能与监控 | JEP 519: 紧凑对象头 | 正式 | 减少内存占用,提高缓存效率 |
| JEP 514, 515: AOT 命令行易用性与方法分析 | 正式 | 简化 AOT 编译,加速应用启动 | |
| JEP 521: 分代 Shenandoah GC | 正式 | 减少垃圾回收停顿时间,提高吞吐量 | |
| JEP 509, 518, 520: JFR 增强 | 实验/正式 | 更精确的 CPU 时间分析、协同采样、方法计时与跟踪,优化性能 |
🧬 语言与语法改进
Java 25 在语言层面引入了多项改进,旨在让代码更简洁、更安全,同时降低初学者的入门门槛。
原始类型模式匹配(JEP 507, 第三预览版):允许在
instanceof和switch中直接使用原始类型模式,简化代码并减少显式类型转换。1
2
3
4
5
6
7
8
9
10// 旧写法:需要显式转换
if (obj instanceof Integer) {
int intValue = (Integer) obj;
System.out.println("Integer: " + intValue);
}
// Java 25 新写法:直接使用原始类型模式
if (obj instanceof int i) { // 如果 obj 是 Integer,则自动拆箱为 int 并赋值给 i
System.out.println("It's an int: " + i);
}模块导入声明(JEP 511, 正式):允许使用
import module语句一次性导入一个模块导出的所有包,简化模块化开发中的依赖声明。1
2
3
4
5
6
7
8
9
10
11// 一次性导入 java.sql 模块导出的所有包
import module java.sql;
// 但如果多个模块导出同名类,仍需显式导入特定类以避免歧义
import java.sql.Date; // 明确指定使用 java.sql.Date
public class Main {
public static void main(String[] args) {
Date sqlDate = Date.valueOf("2025-09-18"); // 使用 java.sql.Date
}
}紧凑源文件和实例 main 方法(JEP 512, 正式):允许省略类声明,直接使用实例
main方法编写程序,极大降低了初学者入门门槛,也适合编写小型脚本。1
2
3
4// 无需声明类!可以直接写 main 方法
void main() {
System.out.println("Hello, Java 25!");
}灵活的构造函数体(JEP 513, 正式):允许在构造函数中调用
super()或this()之前执行必要的语句(如参数验证),使对象构造更安全、更自然。1
2
3
4
5
6
7
8
9
10
11
12class Employee extends Person {
final String name;
Employee(String name, int age) {
// 在调用 super() 之前进行参数验证
if (age < 18 || age > 67) {
throw new IllegalArgumentException("Invalid age for an employee.");
}
super(age); // 验证通过后再调用父类构造函数
this.name = name;
}
}
🔧 API 增强
Java 25 对一些重要的 API 进行了增强和正式化。
作用域值(Scoped Values, JEP 506, 正式):提供了比传统
ThreadLocal更轻量、更高效且不可变的线程内数据共享机制,特别适合与虚拟线程和结构化并发配合使用。1
2
3
4
5
6
7
8
9
10// 定义一个作用域值
static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
// 在特定作用域内绑定值并运行代码
ScopedValue.where(CURRENT_USER, "Alice").run(() -> {
System.out.println("Current user is: " + CURRENT_USER.get()); // 输出: Alice
});
// 超出作用域后,无法再获取值
// System.out.println(CURRENT_USER.get()); // 这会抛出异常结构化并发(Structured Concurrency, JEP 505, 第五预览版):将多个相关的并发任务视为一个工作单元,简化错误处理和任务取消,提高代码的可靠性和可观测性。
1
2
3
4
5
6
7
8
9
10// 结构化并发 (仍处于预览阶段)
// try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// Future<String> userFuture = scope.fork(() -> fetchUser());
// Future<Integer> orderFuture = scope.fork(() -> fetchOrder());
//
// scope.join(); // 等待所有分支完成
// scope.throwIfFailed(); // 如果有任何失败,抛出异常
//
// return new Response(userFuture.resultNow(), orderFuture.resultNow());
// }Vector API(JEP 508, 第十次孵化):允许开发者表达复杂的向量计算,这些计算会在运行时编译为优化的硬件指令,常用于人工智能推理、科学计算等场景。
🛡️ 安全增强
Java 25 在安全性方面也引入了新的 API 和支持。
加密对象的 PEM 编码(JEP 470, 预览):提供了简便的 API,用于在 PEM 格式和 Java 对象之间转换加密密钥、证书等,简化与现有安全系统的集成。
1
2
3
4
5
6
7
8// PEM 编码 (预览功能)
// 示例:将私钥转换为 PEM 格式 (概念性代码)
// KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
// KeyPair keyPair = keyGen.generateKeyPair();
// PrivateKey privateKey = keyPair.getPrivate();
//
// String pemEncodedPrivateKey = PEMEncoder.encodePrivateKey(privateKey);
// System.out.println(pemEncodedPrivateKey);密钥派生函数 API(JEP 510, 正式):为密钥派生函数(如 HKDF、Argon2)提供了标准 API,是迈向后量子密码学的重要一步。
1
2
3
4
5
6
7
8// 密钥派生函数 API
// 示例:使用 HKDF 从主密钥派生新密钥 (概念性代码)
// SecretKey masterKey = ...; // 你的主密钥
// byte[] salt = ...;
// byte[] info = ...;
//
// KeyDerivationFunction kdf = KeyDerivationFunction.getInstance("HKDF");
// SecretKey derivedKey = kdf.deriveKey(masterKey, 256, salt, info);
⚡ 性能与监控改进
Java 25 在运行时性能、内存效率和监控方面也带来了多项优化。
紧凑对象头(JEP 519, 正式):在 64 位平台上将对象头大小从 128 位压缩至 64 位,减少了内存占用,并可能提高缓存效率。
AOT(提前编译)增强(JEP 514, 515, 正式):改进了 AOT 编译的命令行易用性,并支持通过方法分析信息生成更优的本地代码,加速应用启动速度。
分代 Shenandoah 垃圾收集器(JEP 521, 正式):Shenandoah GC 现在正式支持分代模式,通过更频繁地收集年轻代对象,进一步降低停顿时间,提高吞吐量。
JFR(JDK Flight Recorder)增强:
- JFR CPU 时间分析(JEP 509, 实验性):在 Linux 上提供更精确的 CPU 时间分析信息,帮助定位性能瓶颈。
- JFR 协同采样(JEP 518, 正式):改进异步采样堆栈跟踪的稳定性,减少性能开销。
- JFR 方法计时与跟踪(JEP 520, 正式):通过字节码增强支持方法级别的时间分析和跟踪,便于深度性能剖析。
🧪 其他重要更新
- 稳定值(Stable Values, JEP 502, 预览):引入了“稳定值”的概念,允许不可变数据对象享受与
final字段类似的性能优化(如常量折叠),但在初始化时机上又具有灵活性。 - 移除 32 位 x86 端口(JEP 503):移除了对 32 位 x86 架构的支持,以集中资源维护更现代的平台。
🚀 如何尝试 Java 25
- 下载 JDK:从 Oracle 官网 或 Adoptium 等渠道下载 JDK 25。
- 在 IDE 中配置:以 IntelliJ IDEA 为例,在 Project Structure 中下载或指定 JDK 25,并将语言级别设置为
25(对于预览特性,需设置为25 (Preview))。 - 使用预览特性:要使用预览特性,在编译和运行时需显式添加参数:
1
2javac --release 25 --enable-preview YourClass.java
java --enable-preview YourClass
💎 总结与建议
Java 25 作为最新的 LTS 版本,带来了许多令人兴奋的改进:
- 对初学者更友好:紧凑的源文件和实例
main方法显著降低了学习门槛。 - 并发编程模型现代化:作用域值(正式)和结构化并发(预览)与虚拟线程配合,为高并发应用提供了更强大的工具。
- 性能持续提升:紧凑对象头、分代 Shenandoah GC 和 AOT 改进等,从不同角度优化了性能。
- 安全性增强:新的 PEM 编码和 KDF API 适应了现代安全需求。
- 语言表达力更强:原始类型模式匹配、灵活的构造函数等让代码更简洁安全。
给你的建议:
- 对于新项目,特别是微服务、云原生或涉及大量 I/O 并发及AI计算的场景,可以考虑直接从 Java 25 LTS 开始。
- 对于现有项目,升级前务必充分测试,尤其是注意依赖库的兼容性。可优先评估作用域值、灵活构造函数等特性带来的好处。
- 对于初学者,JEP 512 使得入门 Java 变得更加简单。
