Java Record使用指南
- Java Record 使用指南
-
- 一、Record 的核心优势
-
- 1. 代码简洁性
- 2. 不可变性保证
- 3. 自动生成样板代码
- 4. 与密封接口完美配合
- 二、什么时候使用 Record
-
- ✅ 适合场景
-
- 1. DTO(数据传输对象)
- 2. VO(值对象)
- 3. 配置对象
- 4. 集合操作的返回值
- 5. JSON-RPC 消息
- 6. 事件对象
- 7. 数据库查询结果
- ❌ 不适合场景
-
- 1. 需要可变状态的实体
- 2. 需要继承的场景
- 3. 需要延迟初始化或复杂构造逻辑
- 4. 需要 setter 方法
- 三、Record 的高级用法
-
- 1. 添加参数校验
- 2. 添加自定义方法
- 3. 添加静态工厂方法
- 4. 实现接口
- 5. 嵌套 Record
- 四、Record 与 Lombok 对比
-
- 建议
- 五、最佳实践
-
- ✅ 推荐
- ❌ 避免
- 六、总结
-
- 使用 Record 的时机
- 不使用 Record 的时机
Java Record 使用指南
一、Record 的核心优势
1. 代码简洁性
// 传统 class:50+ 行
public class User {
private final String name;
private final int age;
// + 构造函数 + getter + equals + hashCode + toString
}
// Record:1 行
public record User(String name, int age) {}
2. 不可变性保证
- 所有字段自动声明为 private final
- 创建后无法修改,天然线程安全
- 适合并发编程场景
3. 自动生成样板代码
- 私有 final 字段
- 全参构造函数
- 访问器方法(name() 而非 getName())
- equals()、hashCode()、toString()
4. 与密封接口完美配合
public sealed interface Message permits Request, Response {}
public record Request(String method, Object params) implements Message {}
public record Response(Object result) implements Message {}
二、什么时候使用 Record
✅ 适合场景
1. DTO(数据传输对象)
public record UserDTO(String name, String email, Integer age) {}
2. VO(值对象)
public record Money(BigDecimal amount, String currency) {}
public record DateRange(LocalDate start, LocalDate end) {}
3. 配置对象
public record DatabaseConfig(String url, String username, String password) {}
4. 集合操作的返回值
public record PageResult<T>(List<T> data, long total, int page) {}
// 使用
PageResult<User> result = userService.getPage(1, 10);
System.out.println("总数:" + result.total());
5. JSON-RPC 消息
public record JSONRPCRequest(String jsonrpc, String method, Object id, Object params) {}
public record JSONRPCResponse(String jsonrpc, Object id, Object result, JSONRPCError error) {}
6. 事件对象
public record UserCreatedEvent(String userId, String email, Instant timestamp) {}
7. 数据库查询结果
public record UserSummary(String name, long orderCount, BigDecimal totalAmount) {}
❌ 不适合场景
1. 需要可变状态的实体
// ❌ 不适合:实体需要修改状态
public record UserEntity(String name, int age) {}
UserEntity user = new UserEntity("张三", 25);
// user.setName("李四"); // 编译错误!
// ✅ 应该使用传统 class 或 Lombok
@Data
public class UserEntity {
private String name;
private int age;
}
2. 需要继承的场景
// ❌ Record 不能继承其他类
public record AdminUser(String name, String role) extends User {} // 编译错误!
// ✅ 使用传统 class
public class AdminUser extends User {
private String role;
}
3. 需要延迟初始化或复杂构造逻辑
// ❌ Record 的构造函数必须初始化所有字段
public record ComplexObject(LazyField field) {
// 无法实现延迟初始化
}
// ✅ 使用传统 class
public class ComplexObject {
private LazyField field;
public LazyField getField() {
if (field == null) {
field = new LazyField(); // 延迟初始化
}
return field;
}
}
4. 需要 setter 方法
// ❌ Record 没有 setter
public record Config(String value) {}
Config config = new Config("old");
// config.setValue("new"); // 编译错误!
// ✅ 使用传统 class 或 Lombok
@Data
public class Config {
private String value;
}
三、Record 的高级用法
1. 添加参数校验
public record Email(String value) {
// 紧凑构造函数
public Email {
if (!value.contains("@")) {
throw new IllegalArgumentException("无效的邮箱地址");
}
}
}
2. 添加自定义方法
public record DateRange(LocalDate start, LocalDate end) {
public boolean contains(LocalDate date) {
return !date.isBefore(start) && !date.isAfter(end);
}
public long days() {
return ChronoUnit.DAYS.between(start, end);
}
}
3. 添加静态工厂方法
public record Money(BigDecimal amount, String currency) {
public static Money of(double amount, String currency) {
return new Money(BigDecimal.valueOf(amount), currency);
}
public static Money CNY(double amount) {
return of(amount, "CNY");
}
}
// 使用
Money money = Money.CNY(100.00);
4. 实现接口
public interface Comparable<T> {
int compareTo(T o);
}
public record Student(String name, int score) implements Comparable<Student> {
@Override
public int compareTo(Student other) {
return Integer.compare(this.score, other.score);
}
}
5. 嵌套 Record
public record Order(
String orderId,
List<OrderItem> items,
Address shippingAddress
) {
public record OrderItem(String productId, int quantity, BigDecimal price) {}
public record Address(String city, String street, String zipCode) {}
}
四、Record 与 Lombok 对比
| 语言支持 | 原生 Java 16+ | 需要 Lombok 依赖 |
| IDE 支持 | 原生支持 | 需要安装插件 |
| 编译速度 | 更快 | 稍慢(注解处理) |
| 不可变性 | ✅ 强制 | ✅ 强制 |
| 可变性支持 | ❌ 不支持 | ⚠️ 不推荐 |
| 继承 | ❌ 不能继承类 | ✅ 可以继承 |
| 构造函数 | 只能全参 | 支持多种 |
| Builder 模式 | 需手写 | ✅ @Builder |
建议
- Java 16+ 项目:优先使用 Record
- 需要灵活性:使用 Lombok
- 简单数据载体:Record
- 复杂业务对象:Lombok 或传统 class
五、最佳实践
✅ 推荐
命名规范
// ✅ 使用名词命名
public record UserDTO(...) {}
public record OrderSummary(...) {}
// ❌ 避免动词
public record getUser(...) {}
保持简洁
// ✅ 字段少而精
public record Point(int x, int y) {}
// ❌ 字段过多(考虑拆分)
public record User(long f1, long f2, ..., long f20) {}
添加必要的校验
public record Age(int value) {
public Age {
if (value < 0 || value > 150) {
throw new IllegalArgumentException("年龄不合法");
}
}
}
配合密封接口使用
public sealed interface Result<T>
permits Success, Failure {
T getOrNull();
}
public record Success<T>(T value) implements Result<T> {
@Override
public T getOrNull() { return value; }
}
public record Failure<T>(String error) implements Result<T> {
@Override
public T getOrNull() { return null; }
}
❌ 避免
不要在 Record 中存储大量数据
// ❌ 不适合
public record LargeData(byte[] data1, byte[] data2, ...) {}
// ✅ 考虑使用传统 class 或流式处理
不要在 Record 中存储可变对象引用
// ❌ 虽然 Record 不可变,但引用的对象可变
public record Config(List<String> items) {}
Config config = new Config(new ArrayList<>());
config.items().add("hack"); // 破坏了不可变性!
// ✅ 使用不可变集合
public record Config(List<String> items) {
public Config {
items = List.copyOf(items); // 防御性拷贝
}
}
六、总结
使用 Record 的时机
✅ 纯数据载体(DTO、VO、配置) ✅ 需要不可变性 ✅ 不需要继承 ✅ 字段数量适中 ✅ 配合密封接口使用
不使用 Record 的时机
❌ 需要可变状态 ❌ 需要继承其他类 ❌ 需要延迟初始化 ❌ 需要 setter 方法 ❌ 字段过多(> 10 个)
网硕互联帮助中心





评论前必须登录!
注册