--- title: "03-JDK9-21新特性速览" created: 2026-09-03 tags: - Java --- # JDK9-21新特性速览 > [!note] 本篇定位 > 从 9 到 21,Java 改成了"半年一小版本、三年一 LTS"的发版节奏(8/11/17/21 是 LTS)。本篇不逐条罗列 JEP,只挑**日常写代码真正会用到的**,每个特性讲"解决什么 + 语法长什么样"。入门级的新特性(Lambda/Stream)见 [[07-Lambda与函数式接口|07-Lambda与函数式接口]] 及其后篇。 ## 一、var:局部变量类型推断(JDK 10) ```java var list = new ArrayList(); // 右边类型一目了然,左边免写 var map = new HashMap(); ``` 规则与边界:仅限**局部变量**(方法内),且必须**声明时初始化**;字段、方法参数、返回类型都不能用 var。`var list = new ArrayList<>()` 会把元素推断成 `Object`,别在钻石符号里偷懒。 适合直觉判断:类型名太长重复、右边即自明。过度使用会牺牲可读性——`var x = getResult()` 没人知道 x 是什么。 ## 二、文本块(JDK 15 正式):多行字符串 ```java String json = """ { "name": "Java", "version": 21 } """; // 三个双引号包裹,内部引号不用转义,换行原样保留 ``` 解决 SQL、JSON、HTML 拼字符串的转义地狱。配合 `\` 行末续行(下一行不换行)、`\s` 保留行尾空格。 ## 三、record:不可变数据载体(JDK 16 正式) ```java public record Point(int x, int y) { } // 一行搞定 Point p = new Point(1, 2); p.x(); // 访问器方法叫 x(),不是 getX() p.equals(new Point(1, 2)); // true:自动实现 equals/hashCode/toString ``` 编译器自动生成:私有的 final 字段、规范构造器、`equals()`/`hashCode()`/`toString()`、访问器方法。语义就是"**不变的纯数据**"——DTO、VO、返回值、Map key 的天然选择。 它可以有自定义成员: ```java public record Point(int x, int y) { public static final Point ORIGIN = new Point(0, 0); public double distanceFromOrigin() { return Math.hypot(x, y); } // 实例方法 } ``` **与老方案对比**:比手写 POJO 省 80% 模板代码;比 `@Data` 类的本质区别——record 字段**真不可变**(不可变对象线程安全、可放心当 Map key,见 [[01-封装|01-封装]] 的"不可变对象")。 ## 四、sealed:密封类(JDK 17 正式) ```java sealed interface Shape permits Circle, Rectangle { } record Circle(double r) implements Shape { } record Rectangle(double w, double h) implements Shape { } // 未在 permits 列表里的类无法实现 Shape ``` 控制"谁能继承/实现我",配合 switch 模式匹配做**穷尽性检查**——编译器知道所有子类,switch 就不用写 default。sealed 是继承的"白名单",与 final(全禁止)、open(全开放)构成继承控制的三档。 ## 五、switch 表达式与模式匹配 **箭头语法 + 返回值(JDK 14)**: ```java String desc = switch (day) { case MONDAY, FRIDAY -> "忙"; case SATURDAY, SUNDAY -> "休"; default -> "普通"; }; ``` **instanceof 模式匹配(JDK 16)**: ```java if (obj instanceof String s && s.length() > 5) { // 一步完成类型判断+强转+命名 System.out.println(s); } ``` 老的写法 `obj instanceof String` + `(String) obj` 两步合成一步,且 `s` 的作用域精确到条件成立的分支。 **switch 模式匹配(JDK 21)**:把上面两者结合,switch 直接匹配类型并解构 record: ```java static void describe(Object obj) { switch (obj) { case Point(int x, int y) -> System.out.println("点(" + x + "," + y + ")"); case String s -> System.out.println("字符串长度 " + s.length()); case null -> System.out.println("空"); default -> System.out.println("其他"); } } ``` ## 六、虚拟线程(JDK 21,LTS 重磅) ```java // 老:每请求一线程,平台线程昂贵(1MB 栈 + 系统调度) // 新:虚拟线程由 JVM 调度,百万级并发廉价 try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { executor.submit(() -> System.out.println("轻量任务")); } Thread.ofVirtual().start(task); // 或直接起一个虚拟线程 ``` 解决"一连接一线程"模型下线程数上不去的问题:虚拟线程挂起时不占用 OS 线程,IO 密集场景可以轻松开几十万个。**不是银弹**——CPU 密集任务、synchronized 重的代码收益有限。现代 Web 框架(Spring Boot 3.2+)已原生支持。深入见 [[09-Java如何实现协程|09-Java如何实现协程]] 与 [[00-Java并发总览|00-Java并发总览]]. ## 七、其他值得知道的(选讲) - **集合工厂方法(JDK 9)**:`List.of(1,2,3)` / `Map.of("a",1,"b",2)`,不可变集合的简洁创建。已见 [[00-容器总览|00-容器总览]]。 - **Stream API 增强(JDK 9/10/16)**:`takeWhile`/`dropWhile`(顺序流快捷键)、`Stream.toList()`(不可变收集)。 - **`String.strip()`(JDK 11)**:`trim` 只去 ASCII 空格,`strip` 按 Unicode 处理;`isBlank()`(JDK 11)、`lines()`(JDK 11,按行拆分)。 - **`instanceof` + record 的 getter 命名**:record 访问器就是 `x()`,没有 `getX()`——记住这点少踩坑。 - **`Files.readString/writeString`(JDK 11)**:文件读写一次搞定,见 [[09-IO流体系|09-IO流体系]]。 - **Integer/Double 的 `compareUnsigned`**、`Math.clamp`(JDK 21):零散小工具。 ## 八、版本演进一句话地图 ``` JDK 9 模块化(JPMS) + 集合工厂方法 + 私有接口方法 JDK 10 var 局部变量推断 JDK 11 LTS:String.strip/isBlank/lines + java.net.http 标准 HttpClient + ZGC JDK 12-13 switch 表达式预览 JDK 14 switch 表达式正式 + instanceof 模式匹配预览 JDK 15 文本块正式 + ZGC 正式 JDK 16 record 正式 JDK 17 LTS:sealed + 文本块/switch 稳定 JDK 21 LTS:虚拟线程 + switch 模式匹配 + 分代 ZGC ``` **选版本的口径**:新项目起步直接 17 或 21 LTS;老项目 8 迁 17(先清 `Unsafe`/反射/JDK 内部 API 的使用——8 到 9 的模块化是最难跨的一步)。 ## 高频面试题速答 1. **你在用什么版本?为什么?** 21 LTS——虚拟线程、record、switch 模式匹配都稳定了,长期支持。 2. **record 和 POJO 区别?** record 字段 final、自动生成 equals/hashCode/toString、访问器无 get 前缀、不可继承;POJO 可变、模板多。 3. **sealed 有什么用?** 限制继承白名单,配合 switch 做穷尽匹配,编译器帮你查漏。 4. **虚拟线程能替代线程池吗?** 能替代"为 IO 并发开的平台线程池",但 CPU 密集、需严格控制并发度的场景仍要 `Executors.newFixedThreadPool`。 ## 勾连 - 主线的并发知识:[[00-Java并发总览|00-Java并发总览]] - Lambda/Stream 的内容:[[08-Stream与Optional|08-Stream与Optional]] - switch 传统用法与支持类型:[[04-其他关键字|04-其他关键字]] - 深挖 JDK 内部机制:[[01-Class对象与反射机制|01-Class对象与反射机制]] --- ⬅️ [[02-内部类|02-内部类]] 🏠 [[00-Java|00-Java]] ➡️ [[04-设计模式体系|04-设计模式体系]]