Java 14引入record预览特性,需显式启用;Java 16起成为正式特性,专为不可变数据载体设计,自动提供private final字段、public访问器、全参构造器及equals/hashCode/toString实现,并支持静态方法、紧凑构造器等自定义行为以维持不可变语义。

Java 14 引入了 record(预览特性),Java 14–15 中需显式启用预览功能;从 Java 16 开始,record 正式成为语言标准特性,无需额外参数即可直接使用。它专为定义不可变的、仅用于承载数据的类而设计,天然支持封装、不可变性、结构化比较等能力。
record 的基本语法与不可变性保障
record 是一种受限的类(restricted class),编译器自动为其生成:
- 私有 final 字段(对应声明的组件)
- 公共只读访问器方法(
public T fieldName(),不是getXXX()) - 全参数构造器(且不能被重写或隐藏)
-
equals、hashCode、toString的规范实现
例如:
public record Person(String name, int age) {}
这行代码就定义了一个不可变的 Person 类:字段自动是 private final,无法在外部修改,也无法通过继承扩展(record 默认 final),也不允许定义可变状态(如非 final 字段、普通 setter 或非私有可变字段)。
如何添加自定义行为(不破坏不可变性)
record 允许添加静态方法、实例方法、私有辅助方法、注解,甚至紧凑构造器(compact constructor)——但所有操作都必须维持不可变语义:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- 紧凑构造器可用于校验或规范化输入(如拒绝 null、截断字符串),但不能给字段赋值(字段初始化由编译器隐式完成)
- 若需转换逻辑,应返回新 record 实例(如
withAge(int newAge)风格方法) - 禁止定义非
final实例字段,否则编译报错
示例:
public record Person(String name, int age) {
public Person {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("Name cannot be null or blank");
}
if (age
<h3>与传统不可变类(如手写 final class)对比优势</h3>
<p>相比手动编写不可变类,record 更简洁安全:</p>
- 无样板代码:不用手写构造器、getter、equals 等,减少出错可能
- 语义明确:一目了然表明“这是纯数据载体”,IDE 和工具链(如 Lombok 替代方案)能更好支持
- 模式匹配友好:Java 17+ 支持 record 在 switch 模式匹配中解构,进一步强化数据导向编程
- 序列化兼容:默认实现
Serializable(若所有组件可序列化),且满足不可变序列化最佳实践
注意事项与常见误区
使用 record 时需注意:
- record 不适合需要复杂封装逻辑或行为多态的场景(此时仍用普通类)
- 不能继承其他类(隐式继承
java.lang.Record),也不能被继承(final) - 组件类型若为可变引用(如
List),record 本身不可变,但内部对象仍可变 —— 需自行防御性拷贝或使用不可变集合(如List.copyOf()) - 泛型 record 是合法的(如
record Box),类型参数参与 equals/hashCode 计算(T value) {}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










