Record 记录类是什么?它和 Lombok @Data 生成的类有什么区别?
- 标签:Java、新特性
🏛 业务架构师
Record(JDK 16 转正)是 Java 的数据载体类:一行声明 record Order(String id, BigDecimal amount) {} 自动获得构造器、访问器(amount() 而非 getAmount())、equals/hashCode/toString——语义是"我即我的数据"(不可变的值对象)。
与 Lombok @Data 的区别,我从架构治理角度讲:
- 语言级 vs 编译器魔法:Record 是语言特性,任何工具链(编译器、IDE、反射、序列化框架、GraalVM AOT)原生理解;Lombok 依赖注解处理器改写字节码——IDE 插件、新版本 JDK 适配、升级构建工具时的兼容性问题团队都领教过,是长期维护的隐性成本;
- 不可变性是设计哲学而非选项:Record 天生 final、字段 final、无 setter——强制"数据创建了就不变",天然适合并发共享与值语义传递;@Data 默认生成 setter,可变对象在并发和缓存场景是 bug 温床;
- 语义表达力:Record 明确声明"这是纯数据载体",框架(Spring、Jackson)按此优化(如解构、模式匹配配合);Lombok 类仍然是普通类,享受不到语言演进红利(record 模式匹配、紧凑构造校验);
- 依赖治理:新项目用 Record 可以少一个 Lombok 依赖——少一个依赖就少一类升级风险。
我的建议:DTO、值对象、配置项、Map 结构的替代——新代码一律 Record;需要可变对象或 JPA 实体(代理与懒加载需要)的场景保留普通类。Lombok 不必立即清除,但新模块不再引入,逐步自然退役。
🏗 系统架构师
Record(JDK 16)= 不可变数据载体的紧凑声明:一行定义"状态 + 访问器 + equals/hashCode/toString"。
java
public record Point(int x, int y) {} // x(), y(), equals, hashCode, toString 全部生成与 Lombok @Data 的区别(架构视角的关键差异):
- 语义层级:Record 是语言级的数据建模——声明即语义承诺(浅不可变、透明载体);Lombok 是编译期代码生成——把普通类改造成"看起来像数据类",但本质仍是可变 JavaBean(@Data 含 setter,可变性留着);
- 不可变性:Record 字段 final、无 setter、反序列化防篡改语义清晰;@Data 默认全可变——并发共享场景 Record 天然线程安全,DTO 边界防"半更新"状态;
- 组件 vs 字段:Record 的构造参数就是"状态描述"(compact constructor 做校验),API 面(
x())与字段解耦;Lombok 生成 getter/setter 对(贫血模型的惯性); - 依赖与生态:Record 零依赖、IDE/工具链原生支持(pattern matching、deconstruction 仅对 record 生效);Lombok 靠注解处理器 hack 编译器,JDK 升级常出兼容问题(各大版本踩坑史);
- 限制:Record 不能继承(可实现接口)、字段即全部状态、不适合 JPA 实体(JPA 需要可变代理/no-arg constructor)。
我的实践:DTO/VO/值对象/Map 结构的替代 → 一律 Record(配合解构模式匹配);JPA 实体、确实需要可变的构建过程 → Builder(Java 也有生成器方案或保留 Lombok @Builder)。Record + sealed interface + pattern matching 是 Java 数据建模的现代三件套。
💻 全栈开发专家
Record(JDK 16 正式):不可变数据载体的透明final类,一行声明自动生成构造器、getter(无 get 前缀)、equals/hashCode/toString。
java
public record Order(String orderId, BigDecimal amount, OrderStatus status) { }和 Lombok @Data 的区别(工程对比):
| Record | Lombok @Data | |
|---|---|---|
| 语义 | 不可变(final 字段、无 setter) | 可变(有 setter) |
| equals/hashCode | 基于全部组件、语义正确 | 字段生成,浅比较 |
| 继承 | 隐式 final,不能继承别的类 | 普通类可继承 |
| 依赖 | 语言原生、零依赖 | 注解处理器,IDE/构建链要装插件 |
| 反序列化 | Jackson/Gson 原生支持 | 需 Lombok 配合 |
| 构造校验 | 紧凑构造器天然位置 | @Builder+手动校验 |
我的实践立场:DTO/值对象/接口返回体一律 Record——不可变带来线程安全和心智负担的双降;实体(JPA Entity)继续普通类/Bean(可变+懒加载需要 setter);Lombok 在新项目里只剩 @Builder/@RequiredArgsConstructor 还有市场,数据类职责基本被 Record 接管。
加分细节:紧凑构造器做校验:
java
public record Money(BigDecimal amount, String currency) {
public Money { // 紧凑构造器
Objects.requireNonNull(amount);
if (amount.signum() < 0) throw new IllegalArgumentException();
amount = amount.setScale(2, RoundingMode.HALF_UP);
}
}