Java 14 引入了一种名为记录
的类创建新方法,在本教程中,我们将学习:
- 为什么我们需要Java记录
- 如何创建记录并使用它
- 重置和扩展记录类
推荐阅读: [Java 14 功能]( / 社区 / 教程 / Java-14 功能)
为什么我们需要Java记录?
Java 最常见的抱怨之一是它的词汇性. 如果你需要创建一个简单的 POJO 类,它需要以下的锅炉板代码。
- 私人字段
- Getter 和 Setter 方法
- Constructors
- hashCode(),等于(),和 toString() 方法
这种词汇性是对Kotlin(/社区/教程/kotlin)和Project Lombok(/社区/教程/java-project-lombok)的高兴趣的一个原因。
事实上,每次写这些通用方法的纯粹失望导致在Java IDEs中创建它们的捷径,如Eclipse和IntelliJ IDEA。
以下是显示 Eclipse IDE 选项的屏幕截图,以生成一类的仪式方法。
Java 记录旨在通过提供一个紧凑的结构来创建 POJO 类来消除这种词汇性。
如何创建Java记录
Java 记录是一个预览功能,它是在 JEP 359下开发的。
- JDK 14 已安装. 如果您正在使用 IDE,那么它必须为 Java 14 提供支持。Eclipse 和 IntelliJ 都已经为 Java 14 提供支持,所以我们在这里很好
- 启用预览功能:默认情况下,预览功能被禁用。
您可以使用--enable-preview -source 14
选项在命令行中启用 Java 14 预览功能。
假设我想创建一个员工模型类别,它将看起来像下面的代码。
1package com.journaldev.java14;
2
3import java.util.Map;
4
5public class Employee {
6
7 private int id;
8 private String name;
9 private long salary;
10 private Map<String, String> addresses;
11
12 public Employee(int id, String name, long salary, Map<String, String> addresses) {
13 super();
14 this.id = id;
15 this.name = name;
16 this.salary = salary;
17 this.addresses = addresses;
18 }
19
20 public int getId() {
21 return id;
22 }
23
24 public String getName() {
25 return name;
26 }
27
28 public long getSalary() {
29 return salary;
30 }
31
32 public Map<String, String> getAddresses() {
33 return addresses;
34 }
35
36 @Override
37 public int hashCode() {
38 final int prime = 31;
39 int result = 1;
40 result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
41 result = prime * result + id;
42 result = prime * result + ((name == null) ? 0 : name.hashCode());
43 result = prime * result + (int) (salary ^ (salary >>> 32));
44 return result;
45 }
46
47 @Override
48 public boolean equals(Object obj) {
49 if (this == obj)
50 return true;
51 if (obj == null)
52 return false;
53 if (getClass() != obj.getClass())
54 return false;
55 Employee other = (Employee) obj;
56 if (addresses == null) {
57 if (other.addresses != null)
58 return false;
59 } else if (!addresses.equals(other.addresses))
60 return false;
61 if (id != other.id)
62 return false;
63 if (name == null) {
64 if (other.name != null)
65 return false;
66 } else if (!name.equals(other.name))
67 return false;
68 if (salary != other.salary)
69 return false;
70 return true;
71 }
72
73 @Override
74 public String toString() {
75 return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", addresses=" + addresses + "]";
76 }
77
78}
Phew,这是70多行自动生成的代码,现在让我们看看如何创建一个员工记录类,这基本上提供了相同的功能。
1package com.journaldev.java14;
2
3import java.util.Map;
4
5public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
6}
哇,这不能比这更短了,我已经喜欢录音课了。
现在,让我们使用javap
命令来弄清楚记录编译时幕后发生了什么。
1# javac --enable-preview -source 14 EmpRecord.java
2Note: EmpRecord.java uses preview language features.
3Note: Recompile with -Xlint:preview for details.
4
5# javap EmpRecord
6Compiled from "EmpRecord.java"
7public final class EmpRecord extends java.lang.Record {
8 public EmpRecord(int, java.lang.String, long, java.util.Map<java.lang.String, java.lang.String>);
9 public java.lang.String toString();
10 public final int hashCode();
11 public final boolean equals(java.lang.Object);
12 public int id();
13 public java.lang.String name();
14 public long salary();
15 public java.util.Map<java.lang.String, java.lang.String> addresses();
16}
17#
如果您想要更多的内部细节,请使用 -v 选项运行 javap 命令。
1# javap -v EmpRecord
关于纪录班级的重要内容
- 记录类是最终的,所以我们不能扩展它
- 记录类 implicitly extend
java.lang.Record
class. - 记录声明中指定的所有字段都是最终的.
- 记录字段是
shallow
不变的,并取决于类型。 例如,我们可以通过访问它来更改地址字段,然后对其进行更新 - 创建一个单一的构造器,包括记录定义中指定的所有字段
- 记录类自动为这些字段提供附加方法。 名称方法与字段名称相同,而不是像通用和常规方法
- 记录类提供
使用Java程序中的记录
让我们来看看我们使用 EmpRecord 类的一个简单的例子。
1package com.journaldev.java14;
2
3public class RecordTest {
4
5 public static void main(String[] args) {
6
7 EmpRecord empRecord1 = new EmpRecord(10, "Pankaj", 10000, null);
8 EmpRecord empRecord2 = new EmpRecord(10, "Pankaj", 10000, null);
9
10 // toString()
11 System.out.println(empRecord1);
12
13 // accessing fields
14 System.out.println("Name: "+empRecord1.name());
15 System.out.println("ID: "+empRecord1.id());
16
17 // equals()
18 System.out.println(empRecord1.equals(empRecord2));
19
20 // hashCode()
21 System.out.println(empRecord1 == empRecord2);
22 }
23}
输出:
1EmpRecord[id=10, name=Pankaj, salary=10000, addresses=null]
2Name: Pankaj
3ID: 10
4true
5false
记录对象的工作方式与任何模型类、数据对象等相同。
扩展唱片制造商
有时,我们希望在我们的 constructor中进行一些验证或登录。例如,员工ID和工资不应该是负面的。 默认制造商不会有这种验证。 我们可以在记录类中创建一个紧凑型制造商。 该制造商的代码将被放置在自动生成的制造商的开始。
1public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
2
3 public EmpRecord {
4 if (id < 0)
5 throw new IllegalArgumentException("employee id can't be negative");
6
7 if (salary < 0)
8 throw new IllegalArgumentException("employee salary can't be negative");
9 }
10
11}
如果我们创建一个 EmpRecord 像以下代码:
1EmpRecord empRecord1 = new EmpRecord(-10, "Pankaj", 10000, null);
我们将获得 Runtime 例外,如:
1Exception in thread "main" java.lang.IllegalArgumentException: employee id can't be negative
2 at com.journaldev.java14.EmpRecord.<init>(EmpRecord.java:9)
记录类可以有方法吗?
是的,我们可以在记录中创建方法。
1public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
2
3 public int getAddressCount() {
4 if (this.addresses != null)
5 return this.addresses().size();
6 else
7 return 0;
8 }
9}
但是,记录是指数据载体,我们应该避免在记录类中使用实用方法,例如,上面的方法可以在实用类中创建。
如果您认为使用方法对于您的记录类是必不可少的,请仔细考虑是否真的需要记录类?
结论
Java 记录是对核心编程功能的欢迎补充,你可以将其视为一个命名
。它旨在创建一个具有紧凑结构的数据载体对象,避免所有的锅炉板代码。