Java 17 是继 Java 11 之后的第二个 LTS(长期支持)版本,于 2021 年 9 月正式发布。对于还在用 Java 8 或 Java 11 的开发者来说,升级到 Java 17 能获得大量语法糖和性能提升。本文结合实际项目场景,带你快速掌握 Java 17 最值得用的几个新特性。
1. Record 类:告别冗余的 POJO
在 Java 17 之前,写一个数据传输对象(DTO)需要大量样板代码:构造函数、getter、equals、hashCode、toString……即使借助 Lombok,也要加一堆注解。Record 类彻底解决了这个问题。
// 传统写法(加上 Lombok 也要这些注解)
@Data
@AllArgsConstructor
public class UserDTO {
private Long id;
private String name;
private String email;
}
// Java 17 Record 写法
public record UserDTO(Long id, String name, String email) {}
一行代码搞定!Record 自动生成:所有字段的访问方法(注意是 id() 而非 getId())、equals()、hashCode()、toString(),以及全参构造函数。
Record 是不可变的,字段默认 final,非常适合用作 API 响应体、事件对象、值对象等场景。在 Spring Boot 项目中,配合 Jackson 使用时记得确保 Jackson 版本支持 Record(2.12+ 即可)。
// 自定义校验逻辑也很简单
public record UserDTO(Long id, String name, String email) {
public UserDTO {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("name 不能为空");
}
}
}
2. Sealed Classes:精确控制继承体系
Sealed 类允许你明确声明哪些类可以继承它,非常适合用来建模有限的业务状态。
// 定义支付结果只有三种可能
public sealed interface PaymentResult
permits PaymentSuccess, PaymentFailed, PaymentPending {}
public record PaymentSuccess(String transactionId, BigDecimal amount) implements PaymentResult {}
public record PaymentFailed(String errorCode, String message) implements PaymentResult {}
public record PaymentPending(String orderId) implements PaymentResult {}
这样做的好处是:IDE 和编译器都知道 PaymentResult 只有这三种实现,在 switch 表达式中可以做完整性检查,不会漏掉某个分支。
3. Pattern Matching for instanceof:消灭强制转型
以前写类型判断代码,总要先 instanceof 再强转,Java 17 把这两步合并了:
// 旧写法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.toUpperCase());
}
// Java 17 新写法
if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}
结合 Sealed Classes,switch 表达式变得极其优雅:
String describe(PaymentResult result) {
return switch (result) {
case PaymentSuccess s -> "支付成功,交易号:" + s.transactionId();
case PaymentFailed f -> "支付失败:" + f.message();
case PaymentPending p -> "处理中,订单号:" + p.orderId();
};
}
编译器会检查是否覆盖了所有子类,漏掉任何一个都会报错,彻底避免了遗漏分支的 bug。
4. Text Blocks:多行字符串不再痛苦
写 SQL、JSON、HTML 模板时,以前要拼接字符串或者用 StringBuilder,现在用 Text Blocks 清爽多了:
// 旧写法
String sql = "SELECT u.id, u.name, o.amount\n" +
"FROM users u\n" +
"JOIN orders o ON u.id = o.user_id\n" +
"WHERE u.status = 'active'\n" +
"ORDER BY o.created_at DESC";
// Text Blocks 写法
String sql = """
SELECT u.id, u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
ORDER BY o.created_at DESC
""";
在 Spring Boot 项目里,写原生 SQL 查询、构造 JSON 请求体、定义邮件模板时,Text Blocks 能大幅提升代码可读性。
5. 实际迁移建议
如果你的项目还在用 Java 8 或 Java 11,升级到 Java 17 的路径其实比想象中平滑:
- Spring Boot 3.x 强制要求 Java 17+,如果你计划升级 Spring Boot,Java 17 是必经之路
- 先升级 JDK,不改代码,跑一遍测试,大多数项目能直接通过
- 逐步用 Record 替换纯数据类,用 Text Blocks 替换多行字符串拼接
- 新功能(Sealed Classes + Pattern Matching)在新模块中引入,不必一次性重构
小结
Java 17 的这些特性不是花哨的语法糖,而是真正解决了日常开发中的痛点:Record 减少样板代码,Sealed Classes 让业务建模更严谨,Pattern Matching 让类型处理更安全,Text Blocks 让多行字符串可读。
对于正在用 Spring Boot 3.x 的项目来说,这些特性已经是标配。如果你还没用上,不妨从下一个新功能模块开始尝试,感受一下现代 Java 的开发体验。