JDK 17 新特性详解 —— Java 的第三个 LTS 版本
JDK 17 于 2021 年 9 月 14 日正式发布,是继 JDK 8 和 JDK 11 之后的第三个长期支持(LTS)版本。本文全面梳理 JDK 17 带来的重要新特性与改进。
目录
为什么 JDK 17 如此重要
JDK 17 是 Java 生态的一个里程碑版本,原因如下:
| 维度 | 说明 |
|---|---|
| LTS 定位 | 长期支持版本,Oracle 提供至少到 2029 年的支持 |
| Spring 生态 | Spring Boot 3.x / Spring Framework 6.x 强制要求 JDK 17+ |
| 性能飞跃 | 相比 JDK 11 有 10%~30% 的性能提升 |
| 现代 Java | 集成了 JDK 12~17 积累的所有语言和 JVM 改进 |
关键事实: 如果你还在用 JDK 8,JDK 17 是迄今为止最值得升级的目标版本。它稳定、快速,并被主流框架广泛支持。
语言特性增强
1. 密封类(Sealed Classes)— JEP 409(正式特性)
密封类允许你控制哪些类可以继承或实现某个类或接口:
// 定义一个密封类,只允许 Dog 和 Cat 继承
public sealed class Animal permits Dog, Cat, Bird {
public String name() { return "动物"; }
}
// permits 列表中的子类必须是 final、sealed 或 non-sealed
public final class Dog extends Animal {
@Override
public String name() { return "狗"; }
}
public final class Cat extends Animal {
@Override
public String name() { return "猫"; }
}
// non-sealed 表示开放继承,不再受限
public non-sealed class Bird extends Animal {
@Override
public String name() { return "鸟"; }
}
// 现在其他类可以自由继承 Bird
public class Sparrow extends Bird { }
优势:
- 编译期类型安全检查 —— 穷尽所有子类,配合
switch表达式实现完美模式匹配 - 适合建模有限状态的领域(订单状态、支付方式等)
2. 模式匹配 for Switch(预览)— JEP 406
首次将模式匹配引入 switch,让类型判断和值提取一气呵成:
// 传统写法 —— 又臭又长
static String formatter(Object o) {
if (o instanceof Integer i) {
return "整数: " + i;
} else if (o instanceof Long l) {
return "长整数: " + l;
} else if (o instanceof Double d) {
return "浮点数: " + d;
} else if (o instanceof String s) {
return "字符串: " + s;
} else {
return "未知类型";
}
}
// JDK 17 模式匹配 switch —— 清爽优雅
static String formatter(Object o) {
return switch (o) {
case Integer i -> "整数: " + i;
case Long l -> "长整数: " + l;
case Double d -> "浮点数: " + d;
case String s -> "字符串: " + s;
default -> "未知类型";
};
}
注意:此特性在 JDK 17 中为第一轮预览,正式版需等到 JDK 21。但值得提前了解。
3. 文本块增强(Text Blocks)— JEP 378
JDK 13~14 作为预览引入,JDK 15 正式发布。JDK 17 中已成为稳定功能:
// JDK 8 时代 —— 痛苦
String json = "{\n" +
" \"name\": \"张三\",\n" +
" \"age\": 28,\n" +
" \"city\": \"北京\"\n" +
"}";
// JDK 17 文本块 —— 自在
String json = """
{
"name": "张三",
"age": 28,
"city": "北京"
}
""";
// 直接写 SQL 不再是噩梦
String sql = """
SELECT u.id, u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'ACTIVE'
ORDER BY o.total DESC
""";
4. Record 类(Records)— JEP 395(正式特性)
JDK 14~15 预览,JDK 16 正式发布。JDK 17 开箱即用:
// 一行代码替代传统 JavaBean 的几十行样板代码
public record User(Long id, String name, String email) {}
// 编译器自动生成:
// - 私有的 final 字段
// - 全参构造器
// - 所有字段的访问器方法(id()、name()、email())
// - equals()、hashCode()、toString()
// - 不可变 —— 字段全部 final
// 使用
var user = new User(1L, "张三", "zhangsan@example.com");
System.out.println(user.name()); // 张三
System.out.println(user); // User[id=1, name=张三, email=zhangsan@example.com]
// 可自定义紧凑构造器
public record User(Long id, String name, String email) {
public User {
if (id == null || id <= 0) throw new IllegalArgumentException("无效的 ID");
if (name == null || name.isBlank()) throw new IllegalArgumentException("名称不能为空");
}
}
最佳实践: Record 非常适合用作 DTO、VO、配置项、返回结果等不可变数据载体。
5. 增强的 instanceof(JEP 394)— 正式特性
模式匹配 instanceof 在 JDK 16 正式发布,JDK 17 已是标准:
// 旧写法 —— 类型检查 + 强制转换,两步分离
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.toLowerCase());
}
// 新写法 —— 一步到位
if (obj instanceof String s) {
System.out.println(s.toLowerCase());
}
// 支持复杂条件(注意 && 短路语义)
if (obj instanceof String s && s.length() > 5) {
System.out.println("长字符串: " + s);
}
6. Switch 表达式(Switch Expressions)— JEP 361
JDK 12~13 预览,JDK 14 正式发布:
// 传统 switch —— 容易因遗漏 break 导致 fall-through 错误
String dayType;
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
dayType = "工作日";
break;
case SATURDAY:
case SUNDAY:
dayType = "周末";
break;
default:
throw new IllegalArgumentException("无效: " + day);
}
// 新 switch 表达式 —— 安全、精简、可直接赋值
String dayType = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "工作日";
case SATURDAY, SUNDAY -> "周末";
};
库与 API 更新
1. 增强的伪随机数生成器(JEP 356)
全新的 RandomGenerator 接口,提供多种算法实现:
// 使用不同的随机算法
RandomGenerator rng = RandomGenerator.of("L64X128MixRandom");
System.out.println(rng.nextInt(100));
// 遍历所有可用的算法
RandomGeneratorFactory.all()
.map(RandomGeneratorFactory::name)
.forEach(System.out::println);
// 输出示例: L32X64MixRandom, L64X128MixRandom, L64X128StarStarRandom,
// L128X256MixRandom, L128X1024MixRandom, Xoroshiro128PlusPlus, Xoshiro256PlusPlus...
2. 全新的 java.time 格式引擎(核心改进)
// JDK 17 开始,java.time 使用自定义格式引擎,性能更高
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
System.out.println(formatter.format(now)); // 2026-06-09 11:30:45
3. Stream API 增强
// Stream.toList() —— 直接返回不可变 List,比 collect(Collectors.toList()) 更简洁
List<String> names = users.stream()
.map(User::getName)
.toList(); // JDK 16+ 引入,JDK 17 标配
// mapMulti —— 扁平映射的新方式,避免 Stream<Stream<T>> 中间开销
Stream.of(1, 2, 3)
.mapMulti((num, consumer) -> {
consumer.accept(num);
consumer.accept(num * 10);
})
.forEach(System.out::println);
// 输出: 1, 10, 2, 20, 3, 30
4. List.of() / Set.of() / Map.of() 不可变集合
JDK 9 引入,JDK 17 中已是创建小型只读集合的首选:
List<String> colors = List.of("红", "绿", "蓝");
Set<Integer> nums = Set.of(1, 2, 3);
Map<String, Integer> scores = Map.of("张三", 90, "李四", 85, "王五", 92);
性能与运行时改进
1. 新的 macOS 渲染管线(JEP 382)— Apple Metal 加速
JDK 17 在 macOS 上使用 Apple Metal API 替代过时的 OpenGL,告别了需要 -Djdk.gtk.version=2 的蹩脚配置,UI 渲染更流畅。
2. 向量 API(孵化)— JEP 414
面向 CPU 向量指令集的孵化中 API,适用于机器学习、加密、图像处理等密集计算场景:
// 孵化中模块,需要 --add-modules jdk.incubator.vector 编译
// IntVector va = IntVector.fromArray(SPECIES_256, arrayA, 0);
// IntVector vb = IntVector.fromArray(SPECIES_256, arrayB, 0);
// IntVector vc = va.add(vb);
3. ZGC 增强
- 并发线程栈处理
- 更低延迟的垃圾回收
- macOS 与 Windows 平台的全面支持
4. G1 和 Parallel GC 持续优化
- 更好的 NUMA 感知
- 大页内存支持改进
- 更快的 Full GC
5. 外部函数与内存 API(孵化)— JEP 412
取代 JNI 的下一代方案,更安全、更高效地调用本地代码和操作堆外内存:
// 孵化中,将来的标准特性
// MemorySegment segment = MemorySegment.allocateNative(100);
// segment.set(ValueLayout.JAVA_INT, 0, 42);
安全性增强
| 特性 | 说明 |
|---|---|
| JEP 411 | 弃用 Security Manager,为最终移除做准备 |
| JEP 415 | 上下文特定的反序列化过滤器,防止反序列化攻击 |
| TLS 1.3 | 全面支持,默认启用 |
| EdDSA 签名 | 支持 Edwards-Curve 数字签名算法(Ed25519、Ed448) |
| 证书吊销检查改进 | CRL 和 OCSP 检查性能与可靠性提升 |
移除与弃用
- Applet API 正式移除 —— 时代的眼泪
- RMI Activation 被弃用
- AOT 编译器 (jaotc) 与实验性 Graal JIT 被移除
- Security Manager 被标记为弃用 (JEP 411)
- 默认禁用密封(封装) 的内部 API(需要
--add-opens)
从 JDK 8/11 迁移指南
推荐迁移路径
JDK 8 ──────► JDK 11 ──────► JDK 17 ──────► JDK 21(下一 LTS)
↑
直接跳迁到 17 也可行(多数项目适用)
常见迁移问题与解决
| 问题 | 说明 | 解决方案 |
|---|---|---|
| 内部 API 访问受限 | 旧项目常依赖 sun.misc.Unsafe 等 |
添加 --add-opens 启动参数 |
-XX:+UseParallelGC 等 GC 选项变化 |
7 之前默认 CMS,8 之后默认 G1 | 检查 GC 日志,按需调整 |
| Lombok 兼容性 | 旧版 Lombok 不支持 JDK 17 | 升级到 Lombok 1.18.22+ |
| Maven/Gradle 版本 | 老版本编译器不支持 Java 17 | Maven ≥ 3.6.3, Gradle ≥ 7.3 |
--illegal-access=permit 不再有效 |
JDK 17 默认强封装 | 使用 --add-opens 精确开放 |
推荐的启动参数(过渡阶段)
# 最小过渡配置
java --add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
-jar your-app.jar
Maven 编译器配置
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
Gradle 配置
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
总结
JDK 17 不是一个”多了几个语法糖而已”的版本,它代表了 Java 现代化的一个重要节点:
- 语言层面: Records、密封类、模式匹配、文本块,让代码更简洁安全
- 性能层面: ZGC、G1、Metal 渲染、向量 API,全面提升运行时表现
- 生态层面: Spring Boot 3 强制 JDK 17 底线,驱动整个行业升级
- 安全层面: 序列化过滤、EdDSA、TLS 1.3 默认化,安全性再上台阶
如果你还在 JDK 8 上”岁月静好”,是时候迈出这一步了。JDK 17 不仅是一个 LTS,更是现代 Java 开发的新基线。
进一步阅读:
– JEP 索引
*最后更新:2026 年 6 月*