使用 Java 17 的记录(record)特性简化数据类的实现

在 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. 使用记录的注意事项

  1. 不可变性:记录的所有字段默认 final,不能在构造后修改。
  2. 字段只能是 public final:不允许显式声明 privateprotected
  3. 不支持继承:记录不能继承自其他类,且只能实现接口。
  4. 构造函数自定义:可以提供自定义构造函数,但必须完成字段的初始化。

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 手动迁移到记录,减少样板代码,提升开发效率。祝你编码愉快!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注