跳转至

record:不可变数据载体#

版本信息

  • 最低 JDK:16(14 预览 → 16 正式,17 LTS GA)
  • JEPJEP 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)
}
  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、值对象、模式匹配载体。

参考#