从啰嗦到优雅——Java record 的代码瘦身术
1. 什么是 record?
在 Java 开发中,我们经常会写大量的 “数据承载类”,这些类通常只有字段、构造方法、getter、equals、hashCode、toString 方法,逻辑很少,更多是用来传输数据(DTO、VO 等)。
以往的写法:
public class User {
private final String name;
private final int age;
public User(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) { /* 省略 */ }
@Override
public int hashCode() { /* 省略 */ }
@Override
public String toString() { /* 省略 */ }
}
啰嗦 + 重复。
从 Java 16 起,record 关键字让我们可以用一句话生成这样的类:
public record User(String name, int age) {}
就是这样,Java 会帮我们自动生成:
private final修饰的字段- 构造方法
getter(方法名就是字段名)equals()、hashCode()、toString()方法
2. record 的特性
-
不可变性
record自动把字段设为final,对象创建后无法修改字段值。User u = new User("Alice", 20); // u.name = "Bob"; // ❌ 编译错误 -
组件(Component)概念
record构造器参数列表就定义了这个类的字段,称为 “组件”。
例如User(String name, int age)中,name和age就是组件。 -
自定义构造器
可以添加额外校验:public record User(String name, int age) { public User { if (age < 0) throw new IllegalArgumentException("Age must be >= 0"); } } -
实现接口
record可以实现接口:public record Point(int x, int y) implements Comparable<Point> { @Override public int compareTo(Point other) { return Integer.compare(this.x, other.x); } } -
不能继承其他类
所有record默认继承java.lang.Record,不可继承普通类,但可实现接口。
3. 使用场景
-
DTO(数据传输对象)
简化类定义,让代码更干净。 -
作为 Map 的 key
自动生成的equals和hashCode适合当键。 -
事件模型(Event Object)
不可变性 + 自动方法,适合表示一个事件的快照。 -
返回多值
用record打包返回多个值:public record Result(int code, String message) {}
4. 注意事项(坑点)
-
不可变 ≠ 真正线程安全
字段是final,但如果字段类型本身是可变对象(比如List),仍然可能被修改:public record Person(String name, List<String> hobbies) {} var p = new Person("Tom", new ArrayList<>(List.of("reading"))); p.hobbies().add("coding"); // ✅ 可以改解决:使用不可变集合包装。
-
序列化问题
某些旧版序列化框架不支持record,升级框架或使用 JSON 序列化。 -
字段命名冲突
组件名不能和record中已有方法名冲突,比如toString。
5. 实战示例
用 record 创建一个不可变的订单对象
public record Order(String id, String product, int quantity, double price) {
public Order {
if (quantity <= 0) throw new IllegalArgumentException("Quantity must be > 0");
if (price < 0) throw new IllegalArgumentException("Price must be >= 0");
}
public double totalPrice() {
return quantity * price;
}
}
class Main {
public static void main(String[] args) {
Order o = new Order("A001", "Java Book", 2, 39.9);
System.out.println(o); // Order[id=A001, product=Java Book, quantity=2, price=39.9]
System.out.println("Total: " + o.totalPrice());
}
}
输出:
Order[id=A001, product=Java Book, quantity=2, price=39.9]
Total: 79.8
6. 总结
record大幅减少样板代码,非常适合 不可变数据类。- 默认生成的
equals/hashCode/toString让数据对象更易用。 - 注意集合字段不可变性和序列化兼容性。
- 在业务中用来定义 DTO、事件对象、多值返回都很高效。
更多推荐


所有评论(0)