Java Record 与数据载体
record 如何表达不可变数据载体:组件、规范构造器、自动 equals/hashCode/toString 的适用边界。
#concept
#growing
#dev
#java
[!info] related notes
Java Record 与数据载体
这个概念为什么出现
大量类只是“把数据捆在一起”:坐标、金额、命令参数、事件载荷。传统手写 getter/equals/hashCode 噪声大。record 自 Java 16 正式支持,用语言机制声明浅不可变数据载体。
[!abstract] 一句话理解
record是浅不可变的数据载体:组件构成状态,自动提供访问器、equals/hashCode/toString 与规范构造器,适合做值对象而非富领域实体中心。
最小可运行示例
场景:下单 API 的命令对象
import java.util.Objects;
public record PlaceOrderCommand(String skuId, int quantity) {
public PlaceOrderCommand {
// 紧凑构造器:校验组件
Objects.requireNonNull(skuId, "skuId");
if (skuId.isBlank()) throw new IllegalArgumentException("skuId blank");
if (quantity <= 0) throw new IllegalArgumentException("quantity");
}
public static void main(String[] args) {
var a = new PlaceOrderCommand("S1", 2);
var b = new PlaceOrderCommand("S1", 2);
System.out.println(a);
System.out.println(a.equals(b));
System.out.println(a.skuId() + " x" + a.quantity());
}
}
建议运行:
javac PlaceOrderCommand.java && java PlaceOrderCommand
期望输出:
PlaceOrderCommand[skuId=S1, quantity=2]
true
S1 x2
结合场景再看三个关注点
- 访问器是
skuId()不是getSkuId()(惯例不同)。 - 紧凑构造器可校验或规范化参数;正常执行到末尾后编译器才把参数赋给组件字段,不能在其中直接给 this.quantity 等字段赋值。\
- 默认 equals 要求同一 record 类且组件相等;数组组件默认按引用身份,不会自动深比较。
核心概念与准确模型
1. 声明
record Point(int x, int y) {}
2. 自动成员
- 私有 final 组件字段
- 访问器、规范构造器
equals/hashCode/toString
3. 限制
- record 类隐式 final,不能被继承,也不能 extends 其它类(隐含继承 Record)。\
- 组件默认不可变(引用指向的对象仍可能可变——浅不可变)
- 可实现接口、可加静态成员/额外实例方法;不能声明额外实例字段。\
边界情况与反直觉行为
- 组件是可变 List 时,外部仍可改内容;可在构造器中用 List.copyOf 取得不可修改的浅拷贝,但元素对象仍可能可变,而且 copyOf 拒绝 null 元素。\
- 反射/序列化框架对 record 支持因版本与库而异。
- 默认浮点组件相等使用 Float.compare/Double.compare 语义,NaN 视为相等、正负零不同;与原始类型 == 不完全一致。
- 自动生成的 toString 会包含组件值,敏感数据不应直接依赖它写日志。
- 不适合生命周期复杂、可变状态机的实体根。\
常见误区
[!warning] 常见误区:record 替代所有 class 有身份、可变生命周期、丰富不变式维护的对象仍用 class。
工程实践
- DTO/命令/事件用 record。
- 集合组件用
List.copyOf护栏。 - 与 JSON 映射时确认库对 record 的支持。
- 需要建造者时仍可手写静态工厂。
本节总结
- record = 语言级值载体
- 浅不可变 + 组件相等
- 选对场景比滥用重要
自测题
- 为什么说 record 是“浅”不可变?
- record 能否 extends 自定义父类?
参考答案
- 组件引用不可变,但引用目标对象内容可能仍可变。
- 不能;只隐式继承 Record 并可实现接口。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| JEP 395 Records | JEP | 设计与语义 |
| Record Classes (Oracle) | 文档 | 用法 |