揭秘 Java Record:更好的数据处理

介绍

Java 通常被认为是一种冗长的语言,即使是简单的任务也需要大量的代码。为了解决这种冗长的问题,Java 第 14 版引入了一个游戏规则改变者——Record 类。

Java 中 Record 的这种特殊添加旨在简化和简化我们编写代码的方式,特别是对于存储模型数据的类。

让我们深入研究 Java 的演变,并了解 Records 的引入如何标志着迈向更简洁、更高效的编码体验的重要一步。

Java记录是一个用于保存和传输数据的简单模型类。此功能是 OpenJDK 项目 Amber 的一部分,旨在通过为 Java 语言带来更具表现力和可读性的语法来提高 Java 开发人员的工作效率。

该记录旨在解决什么具体问题?

想象一下您正在建立一个系统来管理学生信息。在过去的 Java 时代,该方法需要创建一个类,其中加载了字段、构造函数、getter、setter,甚至可能还有 equals()、hashCode() 和 toString() 方法。

对于存储数据的简单任务来说,这是相当多的重复代码。

记录简化了这个过程。它们充当本质上保存数据的类的快速快捷方式。

实用说明

在引入记录之前,创建一个像 Student 这样的简单类来存储学生数据是一个相当冗长的过程。

它涉及手动定义字段、创建 getter 和 setter、构造构造函数以及实现相等比较 equal()、哈希码生成 hashcode() 以及创建字符串表示形式 toString() 的方法。

这种传统方法需要大量的样板代码,甚至可能使一个简单的类变得相当长。

然而,通过记录,这一过程已被简化为简洁的一行声明,从而显着减少了与以数据为中心的类相关的冗长性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.Objects;

public class Student {
    private int studentId;
    private String studentName;
    private String studentAddress;

    public Student(int studentId, String studentName, String studentAddress) {
        this.studentId = studentId;
        this.studentName = studentName;
        this.studentAddress = studentAddress;
    }

    public int getStudentId() {
        return studentId;
    }

    public void setStudentId(int studentId) {
        this.studentId = studentId;
    }

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public String getStudentAddress() {
        return studentAddress;
    }

    public void setStudentAddress(String studentAddress) {
        this.studentAddress = studentAddress;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return studentId == student.studentId &&
                studentName.equals(student.studentName) &&
                studentAddress.equals(student.studentAddress);
    }

    @Override
    public int hashCode() {
        return Objects.hash(studentId, studentName, studentAddress);
    }

    @Override
    public String toString() {
        return "Student{" +
                "studentId=" + studentId +
                ", studentName='" + studentName + '\'' +
                ", studentAddress='" + studentAddress + '\'' +
                '}';
    }
}

引入Record后,只需一行代码,你就将上面近50行代码变成了一行代码。

我们将类的字段传递给记录的参数。剩下的一切都将在后端处理。您无需执行任何其他操作。您只需按照逻辑要求使用该记录即可。

1
public record StudentRecord(int studentId, String studentName, String studentAddress) {}

就是这样。在早期版本的 Java 中,以前需要 50 行代码才能完成的工作现在只需一行代码即可完成。

何时选择记录?

您可能想知道“我什么时候应该使用记录?”好吧,当类的主要作用是存储数据而无需大量额外逻辑时,记录就是完美的。

如果您正在处理配置、数据库数据或只是传递信息,那么记录就是您新的最好的朋友。

但要记住的关键点是:一旦将数据存储在记录中,您将无法修改记录字段中存在的数据。记录中没有设置数据的setter方法。没有机会回去了。

因此,在项目中创建记录时,请务必考虑场景。

关于记录需要记住的一些重要事项

  • 不可变性质:默认情况下,Java 中的记录是不可变的,这意味着一旦设置了它们的值,就无法更改它们。这有助于创建更可预测和线程安全的代码。

  • 自动方法:记录根据记录中声明的字段自动生成 equals()hashCode()toString() 等方法。这显着减少了样板代码。

  • 无显式 getter 和 setter:记录消除了对显式 getter 和 setter 方法的需要。字段本身充当 getter,而记录不支持 setter,因为它们是不可变的。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
      public record Student(int studentId, String studentName, String studentAddress) {
          // Additional methods or fields specific to the Student record can be added here if needed
      }
    
      public class Main {
          public static void main(String[] args) {
              // Create a Student record instance
              Student student = new Student(14, "Gaurav Sharma", "India");
    
              // Attempt to modify a field (this will result in a compilation error)
              // student.studentId(11);  // Uncommenting this line will result in a compilation error
    
              // Accessing fields using the automatically generated getters
              int studentId = student.studentId();
              String studentName = student.studentName();
              String studentAddress = student.studentAddress();
    
              // Printing the retrieved values
              System.out.println("Student ID: " + studentId);
              System.out.println("Student Name: " + studentName);
              System.out.println("Student Address: " + studentAddress);
          }
      }
    
  • 字段顺序很重要:记录声明中的字段顺序定义了自动生成的构造函数中参数的顺序以及 toString() 方法中组件的顺序。

  • 默认为 Final:记录隐式 final ,这意味着它们不能进一步子类化。如果您尝试扩展记录,您将收到编译错误。此限制确保记录的行为(尤其是其自动方法)保持一致。

    1
    2
    3
    4
    5
    
          // Attempting to extend the Student record
          // This will result in a compilation error
          // public class ExtendedStudent extends Student {
          //     // Compilation error: 'ExtendedStudent' cannot inherit from final 'Student'
          // }
    
  • 在Java中,记录可以像常规类一样实现接口。当记录实现接口时,意味着记录类同意为该接口中声明的所有方法提供具体实现。

    在下面的代码中,您可以看到我们有一个名为 Student 的记录,它具有三个字段并实现了 Displayable 接口。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
      interface Displayable {
          void display();
      }
    
      public record Student(int studentId, String studentName, String studentAddress) implements Displayable {
          @Override
          public void display() {
              System.out.println("Student Information:\n" +
                      "ID: " + studentId +
                      "\nName: " + studentName +
                      "\nAddress: " + studentAddress);
          }
    
      }
    

    现在,创建一个记录 Student 对象并调用 Displayable 接口中的重写方法 display()。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      public class Main {
          public static void main(String[] args) {
              // Create a Student record instance
              Student student = new Student(11, "Gaurav Sharma", "India");
    
              // Invoke the display() method to print student information
              student.display();
          }
      }
    

    输出:

    1
    2
    3
    4
    
      Student Information:
      ID: 11
      Name: Gaurav Sharma
      Address: India
    
  • 向后兼容性:虽然 Java 14 中引入了记录,但它们是完全向后兼容的。这意味着您可以在较新的 Java 版本中使用它们,并且仍然可以在旧版本上运行代码,不会出现任何问题。