从 JDK 8 到 JDK 17
好的,这是一份 JDK 17 与 JDK 8 的详细对比。JDK 8 是一个划时代的长期支持(LTS)版本,而 JDK 17 是当前的主流 LTS 版本,两者之间相隔了近 7 年的发展,包含了海量的变化和改进。
我将从多个维度进行对比,并提供代码示例。
一、核心摘要对比表
特性维度 | JDK 8 (2014年3月) | JDK 17 (2021年9月) LTS | 评价与影响 |
发布周期 | 传统大版本模式 | 6个月一个功能版本,3年一个LTS | 根本性变革。JDK 17 是新的快速发布模式下的第二个LTS,包含了更多迭代特性。 |
License | 主要为 Oracle BCL | GPLv2+CPE (OpenJDK) | 重大利好。主流JDK提供商(Oracle, Adoptium, Amazon等)都提供免费的GPL协议生产级JDK。 |
语言特性 | Lambda、Stream API、方法引用、默认方法 | 密封类、模式匹配(instanceof, switch)、文本块、记录类 | 生产力巨大提升。JDK 17 的语法更现代、更简洁,旨在减少模板代码。 |
API 增强 | Stream, Optional, Date/Time API | 新的HTTP客户端、Flight Recorder、Shenandoah/ZGC垃圾收集器 | API 更加丰富和成熟。提供了高性能的网络、监控和垃圾收集能力。 |
性能 | Parallel GC, CMS (已废弃), G1GC | ZGC(亚毫秒级暂停)、Shenandoah(低延迟)、G1GC持续优化 | 巨大飞跃。JDK 17 的垃圾收集器提供了前所未有的低延迟和高吞吐量选择。 |
内存管理 | 元空间(Metaspace)取代永久代 | 增强的元空间管理,弹性元空间 | 减少了内存溢出问题,自动化程度更高。 |
安全性 | 基础安全支持 | 强化加密算法、默认更强的安全策略、弃用旧安全设施 | 更安全,但可能需要调整旧应用的配置。 |
容器支持 | 对容器(Docker)感知不佳 | 完善的容器支持(自动检测CPU和内存限制) | 在容器化环境中运行时,JDK 17 的行为更符合预期。 |
模块化 | 无 | JPMS (Java Platform Module System) | 架构级变革。提供了强大的封装和依赖管理能力,但迁移需要成本。 |
预览/孵化特性 | 无此概念 | 模式匹配、switch表达式、密封类等先作为预览特性引入 | 允许开发者提前体验和反馈未来语言特性,更稳健。 |
二、详细特性对比与代码示例
1. 语言特性
JDK 8 标志特性:Lambda 表达式与 Stream API
这是函数式编程在Java中的引入,极大地简化了集合操作。
// JDK 8: 过滤列表并收集
List<String> names = Arrays.asList("Anna", "Bob", "Chris");
List<String> filteredNames = names.stream().filter(name -> name.startsWith("A")) // Lambda.collect(Collectors.toList()); // Stream API
JDK 9~17 标志特性(示例):
- 记录类 (Records) - JDK 16 正式:简化不可变数据载体的创建。
// JDK 17: 定义一个不可变的User数据对象
public record User(String name, int age) {}// 自动生成构造方法、getter、equals()、hashCode()、toString()
User user = new User("Alice", 30);
System.out.println(user.name()); // 自动生成的getter
System.out.println(user); // 自动生成的良好toString()
对比JDK 8:需要手动编写所有字段、构造方法、getter、equals/hashCode/toString,代码极其冗长。
- 文本块 (Text Blocks) - JDK 15 正式:简化多行字符串的编写。
// JDK 17: 文本块
String json = """{"name": "Alice","age": 30,"hobbies": ["reading", "hiking"]}""";// JDK 8: 丑陋的拼接和转义
String oldJson = "{\n"+ " \"name\": \"Alice\",\n"+ " \"age\": 30\n"+ "}";
- 模式匹配 (Pattern Matching) - instanceof (JDK 16 正式) & switch (JDK 17 预览):简化根据对象类型进行条件判断的代码。
// JDK 17: instanceof 模式匹配
Object obj = "Hello";
if (obj instanceof String s) { // 直接声明变量 sSystem.out.println(s.toUpperCase()); // s 在这里可以直接用
}// JDK 8: 需要额外的显式转换
if (obj instanceof String) {String s = (String) obj;System.out.println(s.toUpperCase());
}
- 密封类 (Sealed Classes) - JDK 17 正式:限制哪些类可以继承或实现某个父类/接口,提供了更严格的模型控制。
// JDK 17: 定义一个密封类,只允许PermittedEmployee和PermittedManager继承
public sealed class Person permits PermittedEmployee, PermittedManager {// ...
}public final class PermittedEmployee extends Person { /* ... */ }
public non-sealed class PermittedManager extends Person { /* ... */ }// 编译错误:'ExternalPerson' 不允许扩展密封类 'Person'
public class ExternalPerson extends Person { /* ... */ }
2. API 与 性能
- 新的HTTP客户端 (JDK 11 正式):替代古老的
HttpURLConnection
,支持 HTTP/2 和 WebSocket,性能更好,API 更现代(异步同步都支持)。
// JDK 17: 使用新的HttpClient
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://httpbin.org/get")).build();
// 同步发送
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
- 垃圾收集器 (GC):
- JDK 8:主流是
G1GC
,CMS
已标记为废弃。Parallel GC
吞吐量好但停顿时间长。 - JDK 17:ZGC 和 Shenandoah 成为主打低延迟的GC,目标是将停顿时间控制在10毫秒以内,甚至亚毫秒级,适用于超大堆内存(TB级别)场景。G1GC 也持续得到优化。
- JDK 8:主流是
- 飞行记录器 (JFR) - JDK 14 正式:原本是商业特性,在 JDK 11 中开源。它是一个极高性能的 profiling 工具,对性能影响极小(通常 <1%),可以用于生产环境监控、诊断性能问题和GC活动。
3. 模块化 (JPMS - JDK 9 引入)
这是 Java 平台最大的架构性变化,旨在解决“JAR Hell”问题,实现强封装。
- JDK 8:所有类都在 classpath 上,public 类可以被任意访问,缺乏隐藏能力。
- JDK 9+:代码被组织成模块,需要在
module-info.java
中明确声明:
- 它依赖哪些其他模块 (
requires
) - 它导出哪些包给其他模块使用 (
exports
) - 它开放哪些包用于反射 (
opens
)
- 它依赖哪些其他模块 (
// 一个简单的 module-info.java 文件
module com.example.myapp {requires java.base; // 隐含依赖,可不写requires java.sql; // 声明依赖java.sql模块requires java.logging; // 声明依赖java.logging模块exports com.example.api; // 导出api包给其他模块使用// com.example.internal 包没有被导出,其他模块无法访问,实现了强封装
}
- 影响:迁移到模块化可能需要工作量,但它带来了更好的可靠性和安全性。对于非模块化应用,JDK 17 依然可以像以前一样从 classpath 运行。
三、如何选择与升级建议
JDK 8 | JDK 17 | |
状态 | 维护阶段尾声 (官方免费公共更新早已结束) | 当前主流LTS,得到所有厂商的长期支持 |
性能 | 良好 | 显著更好(尤其是GC和容器环境) |
安全性 | 高风险,无法获得最新安全补丁 | 高安全,持续获得安全更新 |
成本 | 如需商业支持(如Oracle JDK 8),费用高昂 | 免费(使用Oracle OpenJDK、Eclipse Temurin等构建) |
生态 | 极其稳定,所有老库都兼容 | 绝大部分主流库和框架都已支持 |
升级建议:
- 新项目:无脑选择 JDK 17。你可以立即享受到所有现代语言特性、卓越的性能和免费的长达数年的支持。
- 现有项目:应制定计划向 JDK 17 迁移。这不是一个简单的替换JRE的操作,需要:
- 测试!测试!测试! 全面测试应用的功能和性能。
- 检查第三方依赖:确保你用的框架(Spring等)和库的版本明确支持 JDK 17。
- 关注废弃API:你的代码可能调用了在 JDK 9~17 中被标记为废弃的API(如某些内部API),需要替换为新的推荐API。
- 考虑模块化:对于大型应用,可以考虑利用JPMS进行模块化改造,但这通常是远期目标而非迁移的必要步骤。
总结
从 JDK 8 到 JDK 17 是一次代际升级,而不是简单的版本号变化。它带来了:
- 革命性的语言特性,让代码更简洁、更安全、更富表现力。
- 颠覆性的性能提升,特别是低延迟垃圾收集器。
- 现代化的运维能力,如JFR和容器支持。
- 免费且长期的支持。
虽然升级需要一定的测试和适配成本,但其带来的性能收益、安全性提升和开发效率的飞跃,使得迁移到 JDK 17 对于绝大多数项目和团队来说,都是一项必要且回报丰厚的投资。