为了便于阅读,本文将分为以下几个部分:

- JDK 8:流(Stream)、函数式接口、默认方法、Optional 类
- JDK 9:模块化系统(Jigsaw)、JShell
- JDK 10:局部变量类型推断(var)
- JDK 11:HTTP Client、ZGC 垃圾收集器(实验性)
- JDK 12 & 13:Switch 表达式、Text Blocks(文本块)
- JDK 14 & 15:Record 类型、Sealed Classes(密封类)
- JDK 16:Record、Sealed Classes(最终版本)
- JDK 17:LTS 版本,主要特性为前面版本的累积和稳定
JDK 8:Java 的“文艺复兴”
JDK 8 是 Java 历史上最重要的一次版本更新,引入了大量现代编程范式,彻底改变了 Java 的编写方式。
1. Lambda 表达式与函数式接口
Lambda 表达式让 Java 能够以更简洁的语法实现匿名函数,核心是函数式接口。一个函数式接口是指只有一个抽象方法的接口,例如 Runnable、Callable。
官方文档: Lambda Expressions
代码示例:
Java
// 传统写法:匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from a thread!");
}
}).start();
// JDK 8 Lambda 写法
new Thread(() -> System.out.println("Hello from a lambda thread!")).start();
2. Stream API
Stream API 提供了一种全新的方式来处理集合数据,它支持声明式编程,让你能够像 SQL 一样对集合进行“查询”。Stream 本身是不可变的,并且是懒加载的。
官方文档: Stream API
代码示例:
Java
List<String> names = Arrays.asList("Tom", "Jerry", "Spike", "Tom");
// 筛选出以 "T" 开头的,转换成大写,去重,并打印
names.stream()
.filter(name -> name.startsWith("T")) // 筛选
.map(String::toUpperCase) // 转换
.distinct() // 去重
.forEach(System.out::println); // 遍历打印
3. Optional 类
Optional<T> 是一个容器对象,可以包含或不包含一个非 null 值。它的主要目的是解决空指针异常(NullPointerException),鼓励你以更函数式的方式来处理可能为空的值。
官方文档: Optional Class
代码示例:
Java
String name = "John";
String nullName = null;
Optional<String> optionalName = Optional.ofNullable(name);
Optional<String> optionalNullName = Optional.ofNullable(nullName);
// 使用 orElse,如果值不存在,则提供一个默认值
String result1 = optionalName.orElse("Default"); // "John"
String result2 = optionalNullName.orElse("Default"); // "Default"
// 使用 ifPresent,当值存在时执行一个操作
optionalName.ifPresent(n -> System.out.println("Hello, " + n));
JDK 9:模块化与 JShell
JDK 9 的核心是 Project Jigsaw,旨在解决大型应用中依赖管理混乱的问题,并提高性能。
1. 模块化系统(JPMS)
Java Platform Module System (JPMS) 允许你将代码组织成独立的模块。每个模块都有一个 module-info.java 文件,明确声明它依赖哪些模块,以及它对外暴露哪些包。
官方文档: Java Platform Module System
2. JShell
JShell 是一个交互式的 Java REPL (Read-Eval-Print Loop) 工具。你可以直接在命令行中输入 Java 代码片段并立即执行,无需编写完整的 main 方法。这对于学习 Java 语法或测试代码片段非常有用。
官方文档: JShell Guide
代码示例 (在命令行中):
Bash
> jshell
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell> int sum = 10 + 20;
sum ==> 30
jshell> System.out.println("Hello, JShell!");
Hello, JShell!
JDK 10:局部变量类型推断(var)
var 关键字允许你在声明局部变量时,让编译器根据初始化值自动推断其类型。这能让代码更简洁,但要注意不能用于方法参数、返回值或成员变量。
官方文档: JEP 286: Local-Variable Type Inference
代码示例:
Java
// JDK 9 及之前
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
// JDK 10 以后
var myMap = new HashMap<String, List<String>>();
JDK 11:新 HTTP Client 和 ZGC
JDK 11 是一个 LTS (Long-Term Support) 版本,带来了生产就绪的 HTTP Client 和实验性的 ZGC。
1. HTTP Client
JDK 11 中正式引入了新的 java.net.http.HttpClient,它提供了更现代、更易用的 API 来处理 HTTP 请求,支持同步和异步调用。
官方文档: HTTP Client
代码示例:
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get"))
.GET() // 或 .POST(...)
.build();
// 同步发送请求
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
JDK 12 & 13:Switch 表达式与文本块
1. Switch 表达式
Switch 表达式允许 switch 语句作为表达式使用,并可以直接返回值,消除了传统 switch 中的 break 语句,避免了“穿透”问题。
官方文档: JEP 361: Switch Expressions (Standard)
代码示例:
Java
// JDK 13 以后
String day = "MONDAY";
String result = switch (day) {
case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY" -> "Workday";
case "SATURDAY", "SUNDAY" -> "Weekend";
default -> throw new IllegalArgumentException("Invalid day: " + day);
};
System.out.println(result);
2. Text Blocks(文本块)
文本块提供了多行字符串的支持,使用三个双引号 """ 包围,无需手动转义换行符和引号,极大地简化了多行字符串(如 JSON、SQL)的编写。
官方文档: JEP 378: Text Blocks (Standard)
代码示例:
Java
// 传统多行字符串
String jsonOld = "{n" +
" "name": "John",n" +
" "age": 30n" +
"}";
// 文本块
String jsonNew = """
{
"name": "John",
"age": 30
}
""";
System.out.println(jsonNew);
JDK 14 & 15:Record 与 Sealed Classes
1. Record(记录)
Record 是一种特殊的类,用于创建不可变的数据载体。它自动生成构造函数、访问器、equals()、hashCode() 和 toString() 方法,省去了大量样板代码。
官方文档: JEP 395: Records (Standard)
代码示例:
Java
// 传统数据类
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
//… getter, equals, hashCode, toString…
}
// Record 写法
public record Point(int x, int y) {}
// 使用
Point p1 = new Point(10, 20);
System.out.println(p1.x()); // 访问器自动生成
System.out.println(p1); // toString() 自动生成
2. Sealed Classes(密封类)
Sealed Classes 允许你限制哪些类可以继承一个类或实现一个接口。你使用 sealed 关键字声明一个类,并用 permits 关键字指定允许继承的子类。这为面向对象设计提供了更精细的控制。
官方文档: JEP 409: Sealed Classes (Standard)
代码示例:
Java
// Shape 是一个密封接口,只允许 Circle 和 Square 实现
public sealed interface Shape permits Circle, Square {}
final class Circle implements Shape {}
final class Square implements Shape {}
// Polygon 不能实现 Shape,编译器会报错
// class Polygon implements Shape {}
JDK 16 & 17:最终定型与 LTS
JDK 16 将 Record 和 Sealed Classes 这两个特性最终定型,使其可以用于生产环境。
JDK 17 作为最新的 LTS 版本,将上述所有新特性(如 Record、Sealed Classes、Text Blocks 等)整合并稳定下来。对于企业级应用来说,JDK 17 是一个非常推荐的升级目标,因为它在性能、稳定性和功能上都达到了一个新的高度。
希望这篇文章能帮助你快速了解 JDK 8 到 JDK 17 的演进过程。这些新特性大大提高了 Java 的开发效率和代码质量,值得你在项目中积极尝试。
Comments 29 条评论
JDK8的Stream API真的香,写集合处理代码简洁多了,再也不用写for循环了👍
文章说JDK17是LTS推荐升级,但公司还在用JDK8,升级成本太高了吧?有老项目迁移经验的聊聊
@Zero_零点 LTS升级成本高?我们组花两周搞定,主要是废弃API替换,文档很全
Optional类救我狗命啊,以前NullPointerException看懵了,现在用orElse处理默认值清晰多了。不过新手可能滥用,记得别嵌套太深
Stream API太好用了,处理集合数据效率翻倍,JDK8真是神更新
公司还在用JDK8,升级JDK17要改多少代码啊?求大佬分享迁移坑点
Optional嵌套用多了反而更乱,建议新手先掌握基础再用,别为了用而用
var关键字写代码看着清爽多了,但IDE有时候推断不准有点烦
JDK17 LTS确实香,我们组刚升级完,GC停顿时间直接砍半!
话说Text Blocks写SQL太方便了,再也不用拼接字符串了,感动哭
模块化系统搞不懂,小公司用不到吧?感觉对微服务项目帮助不大🤔
Record类省了我多少样板代码啊,作者写得真及时,催更下篇!
JDK8到17变化太大,老Java人表示学不动了,躺平等JDK20吧
@鹿鹿斑斑 学不动就对了!新技术堆成山,不如专注用好现有版本
Stream和Lambda用顺手后,回看for循环简直像上古代码,太优雅了
@红娘笑 lambda写多了for循环确实像考古,但面试还让手写for,离谱
Stream API用上就回不去了,处理数据流太丝滑了,JDK8真是程序员福音
Text Blocks写JSON再也不用转义了,感动到哭,建议新手直接上JDK17
Record类省了多少getter/setter啊,写DTO简直飞起,催更下篇讲实战
ZGC停顿时间确实降了,但小项目用JDK8够用,升级得看业务场景
var推断不准的时候真想砸键盘,但整体代码清爽多了
Optional别嵌套三层以上,我之前调个空指针调到怀疑人生
JDK17新特性香是香,但公司框架不支持,只能干看着😭
当年一边学Lambda一边翻源码,怀疑自己读的到底是不是Java
看完这timeline,才发现我已经追更Java快十年,老泪纵横😭
公司刚把JDK17挂上测试环境,一回车Logger罢工,原因竟是旧日志框架不认Record的toString格式,踩坑记录+1
HTTP Client太重了,习惯用OkHttp,看改动又得重学
Stream也就写demo爽,真正线上debug才酸爽
Module system像是强行分家,小公司十来个包拆成模块后感觉纯找事👀