自 JDK 17 发布以来,Java 语言已进入语法现代化的快车道。密封类、记录类、文本块、增强模式匹配……这些语言级特性不仅减少了样板代码,更显著提升了代码表达力与开发效率。作为一名两年 JDK 17 实战经验的开发者,本文将结合实践案例,深入解读这些新特性如何改变我们写 Java 的方式。
一、JDK 17:不仅仅是 LTS
JDK 17 是继 JDK 8 和 JDK 11 之后的又一个长期支持(LTS)版本,涵盖了 JDK 9 至 16 的全部演进成果。从模块系统(Jigsaw)到新垃圾收集器,从语法层的改进到运行时性能优化,JDK 17 是 Java 转向现代语言设计的重要标志。
为什么升级到 JDK 17
- 长期支持至 2031 年,适合企业稳定部署;
- 支持多项新语法与语言特性;
- 更安全、更高效的运行时性能。
二、记录类(Record):构建不可变对象的理想工具
在日常业务中,我们常常需要定义用于传输或封装数据的类(如 DTO)。传统 JavaBean 往往冗长繁琐,而记录类彻底简化了这类任务。
传统方式 vs Record
// JavaBean 写法(冗长)
public class User {
private final String username;
private final int age;
public User(String username, int age) {
this.username = username;
this.age = age;
}
public String getUsername() { return username; }
public int getAge() { return age; }
@Override public boolean equals(Object o) { /* ... */ }
@Override public int hashCode() { /* ... */ }
@Override public String toString() { /* ... */ }
}
// Record 写法(只需一行)
public record User(String username, int age) {}
编译器自动为你生成构造方法、访问器、equals()
、hashCode()
和 toString()
,减少模板代码,提升表达力。
不可变数据的新标准
记录类天然不可变,非常适合并发编程与函数式风格:
User user = new User("Alice", 30);
User olderUser = new User(user.username(), user.age() + 1);
三、密封类(Sealed Classes):类型安全的建模利器
密封类提供了一种控制继承关系的手段,使类层次结构更加严谨且可维护。
定义密封类结构
public sealed interface Shape permits Circle, Rectangle, Triangle {}
public final class Circle implements Shape {}
public sealed class Rectangle implements Shape permits Square {}
public non-sealed class Triangle implements Shape {}
通过 permits
显式声明子类,编译器将强制检查类型封闭性,配合 switch
使用时更安全。
领域模型中的应用场景
public sealed interface Payment permits Alipay, WeChatPay, BankTransfer {}
public final class Alipay implements Payment {}
public final class WeChatPay implements Payment {}
public final class BankTransfer implements Payment {}
结合模式匹配 switch
,可以确保处理所有支付方式,消除遗漏风险。
四、模式匹配(Pattern Matching):类型转换再无模板代码
instanceof 改进示例
// 旧写法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// 新写法
if (obj instanceof String s) {
System.out.println(s.length());
}
这不仅简洁,还能减少潜在的类型错误。
switch 语句的新能力
Object input = fetchInput();
String result = switch (input) {
case Integer i -> "数字: " + i;
case String s -> "文本: " + s.toUpperCase();
case User u -> "用户: " + u.username();
default -> "未知类型";
};
五、文本块(Text Blocks):处理多行文本的利器
传统字符串拼接痛点:
String html = "<html>\n" +
" <body>\n" +
" <h1>Hello</h1>\n" +
" </body>\n" +
"</html>";
使用文本块:
String html = """
<html>
<body>
<h1>Hello</h1>
</body>
</html>
""";
支持换行、缩进、引号无需转义,适合用于 SQL、HTML、JSON 等结构化数据。
六、增强 switch 与 var:更简洁的控制流表达
switch 表达式简化控制逻辑
String label = switch (status) {
case "NEW" -> "新建";
case "PROCESS" -> "处理中";
case "DONE" -> "完成";
default -> "未知状态";
};
也支持复杂逻辑:
String message = switch (code) {
case 200 -> { log("成功"); yield "操作成功"; }
case 500 -> { log("错误"); yield "系统错误"; }
default -> "未知错误";
};
var 结合类型推断
var users = new ArrayList<User>();
var map = new HashMap<String, List<User>>();
虽然 var
不影响运行时类型,但可显著减少泛型冗余。
七、更多实用增强特性速览
1. 接口私有方法
public interface Logger {
default void info(String msg) {
log(msg, "INFO");
}
private void log(String msg, String level) {
System.out.println("[" + level + "] " + msg);
}
}
封装通用行为,避免重复代码。
2. Stream 新增方法
List<String> names = users.stream()
.map(User::username)
.filter(n -> n.startsWith("Z"))
.toList();
List<String> allWords = sentences.stream()
.mapMulti((line, sink) -> Arrays.stream(line.split(" ")).forEach(sink))
.toList();
3. 更智能的 NPE 提示
// JDK 17 提示:Cannot invoke "User.getName()" because "user" is null
String name = user.getName();
显著提高调试效率。
4. 支持 ZGC 和外部内存访问
// JVM 参数
-XX:+UseZGC
配合 MemorySegment
可安全操作堆外内存:
try (MemorySegment mem = MemorySegment.allocateNative(64)) {
MemoryAccess.setInt(mem, 0, 123);
int result = MemoryAccess.getInt(mem, 0);
System.out.println(result);
}
结语:现代 Java 的打开方式
Java 正以前所未有的速度演进,JDK 17 是现代化转型的重要标志。这些语法增强不仅降低了编码负担,也让 Java 的表达力直逼 Kotlin、Scala 等现代语言。现在,是时候告别冗长陈旧的 Java 代码,拥抱更加优雅、简洁和强大的现代 Java 了。