Java 17中引入的record关键字是一个重要的新特性,主要用于简化不可变数据类的定义。这个特性最初在Java 14中作为预览特性出现,并在后续版本中不断完善,最终在Java 17中成为了标准的一部分。

record关键字的作用

record关键字用于声明一个不可变的数据类,它主要用于存储数据而非提供复杂的业务逻辑。record类型是一种不可变的、线程安全的类,其属性在构造函数中初始化,并且可以自动生成equals()、hashCode()、toString()等常用方法。这使得开发者可以更加简洁地定义纯粹的数据类型,提高开发效率和代码的可读性。

record关键字的特性

  • 不可变性:record类的所有成员变量都是final的,即一旦初始化之后就不能被修改。这保证了record对象的不可变性,从而也保证了线程安全性。
  • 自动生成方法:record类会自动生成equals()、hashCode()、toString()等常用方法,无需开发者手动编写。
  • 紧凑的语法:record类的定义非常简洁,只需一行代码即可声明一个包含多个属性的不可变类。
  • 构造函数:record类隐式包含一个全参数的构造函数,用于初始化所有成员变量。
  • 访问器方法:对于record类的每个成员变量,都会自动生成一个同名的访问器方法(getter),用于获取该成员变量的值。

record关键字的使用场景

record类型适用于表示数据的纯粹值类型,例如一个不可变的坐标点、一条只读的日志记录等。对于需要复杂业务逻辑或自定义行为的类,仍然推荐使用传统的类定义。

示例代码

下面是一个使用record关键字定义不可变数据类的示例:

package com.morris.java17;

/**
 * record关键字的使用
 */
public class RecordDemo {
    public static void main(String[] args) {
        Point p = new Point(10, 20);
        System.out.println(p); // Point[x=10, y=20]
    }
}

record Point(int x, int y) {
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

反编译class文件如下:

package com.morris.java17;

record Point(int x, int y) {
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int x() {
        return this.x;
    }

    public int y() {
        return this.y;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

record类的构造方法

record同样也有构造方法,可以在构造方法中对数据进行一些验证操作。

package com.morris.java17;

/**
 * record关键字的使用
 */
public class RecordDemo2 {
    public static void main(String[] args) {
        Person p = new Person("morris", 18);
        System.out.println(p); // Point[x=10, y=20]
    }
}

record Person(String name, int age) {
    // 构造方法
    Person {
        System.out.println("name: " + name + ", age: " + age);
        if (name == null) {
            throw new IllegalArgumentException("姓名不能为空");
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

注意事项

  • 不支持继承:record类隐式继承自java.lang.Record,且由于Java不支持多继承,因此record类不能显式继承其他类。
  • 成员变量声明:record类的成员变量只能在构造函数中声明,并且都是final的。
  • 方法定义:虽然可以在record类中定义其他方法,但应确保这些方法不会破坏record的不可变性。