0
点赞
收藏
分享

微信扫一扫

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 关键字定义一个记录类:

record Person(String name, int age) {}

示例代码:

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());
    }
}

输出:

Person[name=Alice, age=25]
Name: Alice
Age: 25

Records 的特点

  1. 自动生成构造函数
  • 编译器会自动为 Record 类生成一个构造函数,包含所有字段。
  • 你可以根据需要自定义构造函数。

record Person(String name, int age) {
    // 自定义构造函数
    public Person {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative");
        }
    }
}

  1. 自动生成访问器方法
  • 每个字段都会自动生成一个对应的访问器方法(getter),方法名与字段名相同。
  • 不需要显式地编写 getName() 或 getAge()

Person person = new Person("Alice", 25);
String name = person.name(); // 访问 name 字段
int age = person.age();      // 访问 age 字段

  1. 自动生成 equals()hashCode()
  • Records 会根据字段值自动生成 equals() 和 hashCode() 方法。
  • 两个 Record 对象相等的条件是它们的所有字段值都相等。

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]

Person person = new Person("Alice", 25);
System.out.println(person); // 输出:Person[name=Alice, age=25]

  1. 不可变性
  • Record 类的字段是隐式 final 的,无法修改。
  • 这使得 Record 类非常适合用作不可变数据对象。

Person person = new Person("Alice", 25);
// person.name("Bob"); // 编译错误:无法修改字段

Records 的限制

  1. 不能继承其他类
  • Record 类隐式继承自 java.lang.Record,因此不能显式继承其他类。

record Person(String name, int age) extends Object {} // 编译错误

  1. 不能声明非静态字段
  • Record 类只能包含声明的组件字段,不能添加额外的实例字段。

record Person(String name, int age) {
    private int id; // 编译错误:不能添加额外的实例字段
}

  1. 不能定义额外的构造函数
  • 只能定义紧凑构造函数(Compact Constructor)或重载构造函数。

record Person(String name, int age) {
    public Person() { // 编译错误:不能定义无参构造函数
        this("", 0);
    }
}

Records 的高级用法

1. 局部类实现接口

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

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 类。

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 类支持泛型。

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() 等方法,极大地简化了代码的编写,同时保证了不可变性和线程安全性。

举报

相关推荐

0 条评论