Java 17 新特性之 Records(记录类)

Java 17 引入了 Records(记录类) ,这是 Java 语言中一种新的类类型,用于简化数据载体类的定义。Records 是不可变的数据类,自动提供了 ​​equals()​​​、​​hashCode()​​​、​​toString()​​ 等方法,从而减少了样板代码的编写。

这一特性最初在 Java 14 中作为预览功能引入,并在 Java 16 中成为正式特性。Java 17 继续支持并优化了这一功能。


为什么需要 Records?

在传统的 Java 开发中,当我们需要创建一个简单的数据载体类时,通常需要编写大量的样板代码,例如:

  • 构造函数
  • ​equals()​ 方法
  • ​hashCode()​ 方法
  • ​toString()​ 方法
  • Getter 方法

这些代码虽然可以通过 IDE 自动生成,但仍然会增加代码的复杂性,降低可读性。

Records 的目标是通过简化的语法,自动生成这些方法,使代码更加简洁和直观。


Records 的基本用法

定义一个 Record 类

使用 ​​record​​ 关键字定义一个记录类:

arduino 复制代码
record Person(String name, int age) {}

示例代码:

csharp 复制代码
public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 25);
        System.out.println(person); // 自动调用 toString()
        System.out.println("Name: " + person.name());
        System.out.println("Age: " + person.age());
    }
}

输出:

makefile 复制代码
Person[name=Alice, age=25]
Name: Alice
Age: 25

Records 的特点

  1. 自动生成构造函数
  • 编译器会自动为 Record 类生成一个构造函数,包含所有字段。
  • 你可以根据需要自定义构造函数。
arduino 复制代码
record Person(String name, int age) {
    // 自定义构造函数
    public Person {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative");
        }
    }
}
  1. 自动生成访问器方法
  • 每个字段都会自动生成一个对应的访问器方法(getter),方法名与字段名相同。
  • 不需要显式地编写 ​getName()​​getAge()​
ini 复制代码
Person person = new Person("Alice", 25);
String name = person.name(); // 访问 name 字段
int age = person.age();      // 访问 age 字段
  1. 自动生成 ​equals() ​ ​hashCode() ​
  • Records 会根据字段值自动生成 ​equals()​​hashCode()​ 方法。
  • 两个 Record 对象相等的条件是它们的所有字段值都相等。
ini 复制代码
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1.equals(p2)); // true
  1. 自动生成 ​toString() ​
  • 编译器会自动生成 ​toString()​ 方法,格式为:​RecordName[field1=value1, field2=value2]​
ini 复制代码
Person person = new Person("Alice", 25);
System.out.println(person); // 输出:Person[name=Alice, age=25]
  1. 不可变性
  • Record 类的字段是隐式 ​final​ 的,无法修改。
  • 这使得 Record 类非常适合用作不可变数据对象。
ini 复制代码
Person person = new Person("Alice", 25);
// person.name("Bob"); // 编译错误:无法修改字段

Records 的限制

  1. 不能继承其他类
  • Record 类隐式继承自 ​java.lang.Record​,因此不能显式继承其他类。
dart 复制代码
record Person(String name, int age) extends Object {} // 编译错误
  1. 不能声明非静态字段
  • Record 类只能包含声明的组件字段,不能添加额外的实例字段。
arduino 复制代码
record Person(String name, int age) {
    private int id; // 编译错误:不能添加额外的实例字段
}
  1. 不能定义额外的构造函数
  • 只能定义紧凑构造函数(Compact Constructor)或重载构造函数。
arduino 复制代码
record Person(String name, int age) {
    public Person() { // 编译错误:不能定义无参构造函数
        this("", 0);
    }
}

Records 的高级用法

1. 局部类实现接口

Record 类可以实现接口,但不能继承其他类。

java 复制代码
interface Greeting {
    void greet();
}

record Person(String name, int age) implements Greeting {
    @Override
    public void greet() {
        System.out.println("Hello, my name is " + name);
    }
}

Person person = new Person("Alice", 25);
person.greet(); // 输出:Hello, my name is Alice

2. 嵌套 Record

可以在其他类中定义嵌套的 Record 类。

arduino 复制代码
class OuterClass {
    record Point(int x, int y) {}
}

OuterClass.Point point = new OuterClass.Point(10, 20);
System.out.println(point); // 输出:Point[x=10, y=20]

3. 泛型 Record

Record 类支持泛型。

sql 复制代码
record Pair<T, U>(T first, U second) {}

Pair<String, Integer> pair = new Pair<>("Alice", 25);
System.out.println(pair); // 输出:Pair[first=Alice, second=25]

适用场景

  1. 数据传输对象(DTO)
  • 在微服务或 API 调用中,常用于封装请求和响应数据。
  1. 不可变对象
  • 当需要创建不可变的对象时,Record 类是一个很好的选择。
  1. 简单实体类
  • 在领域驱动设计(DDD)中,可以用 Record 类表示值对象(Value Object)。
  1. 减少样板代码
  • 替代传统的 POJO 类,减少冗余代码。

总结

Records 是 Java 17 中一项非常实用的新特性,特别适合用来定义简单的数据载体类。它通过自动生成构造函数、访问器方法、​​equals()​​​、​​hashCode()​​​ 和 ​​toString()​​ 等方法,极大地简化了代码的编写,同时保证了不可变性和线程安全性。

相关推荐
LUCIAZZZ27 分钟前
final修饰符不可变的底层
java·开发语言·spring boot·后端·spring·操作系统
wsj__WSJ40 分钟前
Spring Boot 请求参数绑定:全面解析常用注解及最佳实践
java·spring boot·后端
CodeUp.2 小时前
SpringBoot航空订票系统的设计与实现
java·spring boot·后端
码事漫谈2 小时前
Linux下使用VSCode配置GCC环境与调试指南
后端
求知摆渡2 小时前
RocketMQ 从二进制到 Docker 完整部署(含 Dashboard)
运维·后端
没事偷着乐琅2 小时前
spring boot 异步线程@Async 传递 threadLocal数据
java·spring boot·后端
liangdabiao2 小时前
LangGraph大法好:工作流编排框架,特别适合构建复杂的多步骤、有状态或协作式 AI 应用
后端·面试·github
村口弋师傅2 小时前
使用ScheduledExecutorService日志没有traceId问题原因及解决方案
后端
用户1512905452202 小时前
Dbt基本概念与快速入门
后端