Java Records 是 Java 14 引入、Java 16 正式化的特性,用于创建不可变的数据载体类。下面详细说明使用方法:
1. 基本语法
java
public record Point(int x, int y) {}
编译器会自动生成:
- 私有 final 字段(
x,y) - 规范构造函数
- 访问器方法(
x(),y()) equals(),hashCode(),toString()
2. 自定义构造函数
紧凑构造函数(推荐)
java
public record Point(int x, int y) {
public Point {
// 参数验证
if (x < 0 || y < 0) {
throw new IllegalArgumentException("坐标不能为负数");
}
// 无需显式赋值,编译器自动处理
}
}
传统构造函数
java
public record Point(int x, int y) {
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
3. 添加方法
java
public record Point(int x, int y) {
// 实例方法
public double distanceTo(Point other) {
int dx = x - other.x;
int dy = y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
// 静态方法
public static Point origin() {
return new Point(0, 0);
}
}
4. 实际使用示例
java
// 定义Record
public record User(
Long id,
String username,
String email,
LocalDateTime createdAt
) {
public User {
// 验证逻辑
Objects.requireNonNull(username);
Objects.requireNonNull(email);
// 数据转换
email = email.toLowerCase();
}
// 便捷构造函数
public User(String username, String email) {
this(null, username, email, LocalDateTime.now());
}
}
// 使用
public class Main {
public static void main(String[] args) {
// 创建实例
User user = new User(1L, "alice", "ALICE@EXAMPLE.COM", LocalDateTime.now());
// 访问器方法(没有get前缀)
System.out.println(user.username()); // "alice"
System.out.println(user.email()); // "alice@example.com"
// 自动生成的toString()
System.out.println(user);
// 输出: User[id=1, username=alice, email=alice@example.com, ...]
// 解构(Java 21+)
if (user instanceof User(Long id, String name, String email, LocalDateTime time)) {
System.out.println("ID: " + id);
}
}
}
5. 结合其他特性
与 Stream API 结合
java
record Person(String name, int age) {}
List<Person> people = List.of(
new Person("Alice", 25),
new Person("Bob", 30)
);
// 过滤并获取名字
List<String> names = people.stream()
.filter(p -> p.age() > 25)
.map(Person::name)
.toList();
作为 DTO 使用
java
// API 响应
public record ApiResponse<T>(
boolean success,
String message,
T data,
LocalDateTime timestamp
) {}
// 在Spring Boot中作为返回类型
@RestController
public class UserController {
@GetMapping("/users/{id}")
public ApiResponse<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return new ApiResponse<>(true, "成功", user, LocalDateTime.now());
}
}
6. 重要注意事项
-
Record 是 final 的,不能继承其他类
-
可以继承接口
javapublic record Person(String name, int age) implements Serializable, Comparable<Person> { @Override public int compareTo(Person other) { return this.name.compareTo(other.name); } } -
可以有静态字段和方法
-
不能有实例字段(除自动生成的)
-
可以嵌套和泛型化
javapublic record Pair<T, U>(T first, U second) {}
7. 适用场景
✅ 适合使用:
- DTO(数据传输对象)
- 值对象(Value Objects)
- 不可变数据容器
- 方法返回多个值
- 临时数据存储
❌ 不适合:
- 需要可变状态
- 需要继承其他类
- 需要复杂的业务逻辑
- 需要序列化特殊处理
8. Java 21+ 增强
java
// 解构模式匹配
switch (obj) {
case Point(int x, int y) -> System.out.printf("点(%d, %d)", x, y);
case User(String name, int age) -> System.out.println(name);
default -> {}
}
总结
Records 大大简化了数据载体的创建,减少了样板代码,增强了代码可读性和安全性。建议在以下情况优先使用 Record:
- 数据建模(DTO、VO)
- 方法返回多个值
- 需要值语义的简单类
- 不可变数据容器
但要注意,Record 不是所有场景的替代品,复杂的业务逻辑类仍然应该使用完整的类定义。