在 Java 8 之前,想要创建一个简单的数据传输对象(DTO)或值对象,几乎都要写一大堆样板代码:构造函数、getter、setter、equals、hashCode、toString 等。随着 Java 14 开始引入的 record,Java 17 将这一特性正式稳定下来,极大地减少了冗余代码。本文将带你从零开始,演示如何使用记录来快速构建一个不可变的数据类,并比较传统 POJO 的实现方式。
1. 记录(record)的基本语法
public record Person(String name, int age) {}
上面这行代码已经完成了以下所有工作:
- 定义了一个类
Person。 - 为每个字段生成了
private final的实例变量。 - 自动生成了带所有字段参数的构造函数。
- 自动生成了对应的 getter 方法,方法名与字段名一致(
name()、age())。 - 自动实现了
equals(Object)、hashCode()、toString()。
因此,一个简单的数据类只需要一句代码即可。
2. 与传统 POJO 的对比
传统实现
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
可以看到,至少需要 30 行代码。记录让我们在 1 行中完成同样的功能。
3. 记录的优势
| 特性 | 传统 POJO | 记录 |
|---|---|---|
| 不可变性 | 需要手动确保(private + final) | 自动保证 |
| 代码量 | 较多 | 极少 |
| 语义表达 | 需要额外的注释 | 内嵌语义(record 代表值对象) |
| 生成方法 | 手写或 IDE 生成 | 自动生成 equals, hashCode, toString |
| 可读性 | 较高 | 代码更简洁,易读 |
4. 使用记录的注意事项
- 不可变性:记录的所有字段默认
final,不能在构造后修改。 - 字段只能是
public final:不允许显式声明private或protected。 - 不支持继承:记录不能继承自其他类,且只能实现接口。
- 构造函数自定义:可以提供自定义构造函数,但必须完成字段的初始化。
5. 实际案例:JSON 序列化
假设我们需要把 Person 对象转换为 JSON,使用 Jackson 库。
import com.fasterxml.jackson.databind.ObjectMapper;
public class Demo {
public static void main(String[] args) throws Exception {
Person person = new Person("Alice", 28);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"name":"Alice","age":28}
}
}
Jackson 默认支持记录的序列化,甚至无需额外注解即可工作。
6. 进阶:记录与接口的组合
public interface Identifiable {
UUID id();
}
public record Book(String title, String author, UUID id) implements Identifiable {}
这里 Book 既是一个不可变的数据类,又实现了 Identifiable 接口,体现了记录的灵活性。
7. 小结
记录(record)是 Java 17 提供的一项强大功能,专门为简化数据类而设计。它让我们能够以极短的代码实现不可变的值对象,同时保持与传统 POJO 的兼容性。无论是内部数据传输还是外部 API 的 DTO,记录都是一个值得考虑的优选方案。
如果你在项目中仍使用 Java 8 或 11,可以尝试将大批量的 DTO 手动迁移到记录,减少样板代码,提升开发效率。祝你编码愉快!

发表回复