record:不可变数据载体#
版本信息
- 最低 JDK:16(14 预览 → 16 正式,17 LTS GA)
- JEP:JEP 395
为什么需要#
JDK 8 里写一个"纯数据类"要手写私有字段、构造器、一堆 getter、equals/hashCode/toString,几十行几乎全是样板,且极易写错(比如忘了在 equals 里加某个字段)。record 把这一切交给编译器,让你用一行声明一个不可变的数据聚合。
语法#
下面这段是 examples/record/ 里真实可运行的源码(通过 snippets 嵌入,与示例代码零漂移):
package com.javamodern.record;
// 不可变二维点:record 自动生成字段、构造器、访问器、equals/hashCode/toString
public record Point(int x, int y) { // (1)
}
- :material-lightbulb:
record关键字声明一个不可变数据载体;头部(int x, int y)即组件,等价于private final字段。
与 JDK 8 旧写法对比#
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) { this.x = x; this.y = y; }
public int getX() { return x; }
public int getY() { return y; }
public boolean equals(Object o) { /* 省略:约 10 行 */ return false; }
public int hashCode() { /* 省略 */ return 0; }
public String toString() { /* 省略 */ return ""; }
}
public record Point(int x, int y) {}
底层原理#
record 本质仍是 final class,编译器按组件自动生成下列成员,字节码层面与手写等价:
graph LR
R["record Point(int x, int y)"] --> F["private final int x, y"]
R --> C["规范构造器 Point(int,int)"]
R --> A["访问器 x() / y()"]
R --> E["equals / hashCode / toString"]
常见坑 / 最佳实践#
- 紧凑构造器做参数校验:
public Point { if (x < 0) throw new IllegalArgumentException(); }。 - record 可实现接口,但不能继承类(已隐式继承
java.lang.Record)。 - 组件是
final的,不可变;需要可变状态就不要用 record。
小结#
record 用一行换掉了几十行样板,适合 DTO、值对象、模式匹配载体。