背景
随之Java 21正式发布。该版本是继JDK 17之后最新的长期支持版本(LTS),将获得至少8年的支持!而SpringBoot3和Spring6的最低依赖就是JDK17了。
在JAVA8的时代,开发者肯定都使用过Lombok库,这个库大大提升了我们的开发效率,少写了很多代码,但是它也存在很多问题,下面我来细细聊一下。
首先我们看下传统意义上的定义一个类:
public class User { private String userName; private String email; private int userId; public User(String username, String email, int userId) { this.userName = userName; this.email = email; this.userId = userId; } public String getUserName() { return username; } public void setUserName(String userName) { this.userName = userName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (userId != user.userId) return false; if (username != null ? !username.equals(user.userName) : user.userName != null) return false; return email != null ? email.equals(user.email) : user.email == null; } @Override public int hashCode() { int result = userName != null ? userName.hashCode() : 0; result = 31 * result + (email != null ? email.hashCode() : 0); result = 31 * result + userId; return result; } @Override public String toString() { return "User{" + "userName='" + userName + '\'' + ", email='" + email + '\'' + ", userId=" + userId + '}'; } }
而使用Lombok后的代码:
import lombok.Data; @Data public class User { private String userName; private String email; private int userId; }
@Data注解会自动生成所有的getter函数、字段的所有setter函数、toString函数、构造函数、hashCode和equals函数。
@Data 注释结合了其他几个 Lombok 注释,例如 @Getter、@Setter、@EqualsAndHashCode 和 @toString。如果需要,我们还可以单独使用这些注释。
看上去是很美好,不是吗?但是仔细思考下,会发现这些问题:
- 第三方依赖:Lombok是一个第三方库,作为开发人员,我们依赖第三方库来完成这些琐碎的事情。Lombok仅依靠社区支持来维护。如果随着Java 版本的升级可能会存在不兼容性问题或者该库不受支持,则会导致代码库出现问题。
- IDE 兼容性: Lombok 依赖于编译时的代码生成,这可能并不总是与所有集成开发环境 (IDE) 无缝协作。某些 IDE 可能不完全支持 Lombok 功能,从而导致难以识别和理解生成的代码。
那么有什么好的替代方案吗?Record了解一下?
什么是Record?
Record是 Java 中从 Java 14(作为预览功能)开始引入的新功能,并在Java 16中正式引入。Records提供了一种简洁的方法来定义主要用于封装数据的简单类。它们是一种类,可以根据类的字段自动生成常用方法,例如构造函数、 equals()、hashCode()和。toString()
你看到 Record 和 Lombok 之间的相似之处了吗?他们都在帮助我们实现同样的目标。
那么如何使用呢?
要使用 Record 定义上述 User 类,我们只需要这样做。
public record UserRecord(String userName, String email, int userId) { }
就是这样。只需一行代码即可实现我们用 65 行传统编码和 5 行 Lombok 所做的事情。另外,我们不必依赖第三方库。
一旦我们创建了上面的类,除了toString、hashCode和equals等类级别的方法之外,Java内部还定义了三个final变量及其getter方法。
让我们详细讨论Record
一旦我们有了用户Record类,我们就可以开始使用它了。
// Initialize the record. UserRecord userRecord = new UserRecord("test", "test@163.com", 1234); // get the properties System.out.println(userRecord.email()); System.out.println(userRecord.toString());
请注意,getter 方法中没有“get”关键字。我们需要直接使用变量名作为方法名。例如,getEmail()我们不是像传统上那样使用,而是在调用 Record 方法时使用email()。
一旦初始化,我们就无法设置 Record 的属性值。所有变量都是最终的。这意味着记录是不可变的。
我们可以在记录中定义实例和类函数。我们可以定义静态变量。我们不能定义实例变量。
// 类(静态)变量 public static final String invalidEmailMessage = "INVALID EMAIL"; // 实例变量 - 不允许。会抛出错误。 public String defaultEmail = "xxxxx@163.com"; // 类函数 public static void sayMyName() { System.out.println("zhangsan"); } // 实例函数 public String emailDomain() { return this.email.split("@")[1]; }
// 使用对象 userRecord.emailDomain(); // 使用 Class 调用静态方法。 UserRecord.sayMyName();
Record类无法扩展。所有 Record 类都隐式扩展 Record 类。而且Java不允许多重继承。因此我们的 Record 类不能是任何其他类的子类。
默认情况下,记录也是最终记录。因此我们不能将它们用作任何其他类的父类。
记录构造器
该记录声明了一个带有所有参数的默认构造函数。这种类型的构造函数称为规范构造函数。
public UserRecord(String username, String email, int userId) { this.username = username; this.email = email; this.userId = userId; }
我们可以在构造函数中编写自定义逻辑。
public UserRecord(String username, String email, int userId) { this.username = username; this.email = email; this.userId = userId; if (userId < 1) { throw new IllegalArgumentException("UserId can not be less than 1"); } }
有一个很棒的功能,我们可以通过消除不必要的细节来创建一个紧凑的构造函数。例如,上面具有自定义逻辑的规范构造函数可以以紧凑的形式重写为:
public UserRecord { if (userId < 1) { throw new IllegalArgumentException("UserId can not be less than 1"); } }
比较Lombok和Record:
功能 |
Lombok |
Record |
不变性 |
没有 |
是的 |
可扩展性 |
是的 |
没有 |
样板代码 |
减少 |
减少 |
可读性 |
可能会更难阅读 |
更容易阅读 |
稳健性 |
不太稳健 |
更坚固 |
第三方依赖 |
是的 |
没有 |
IDE 兼容性 |
不容易 |
简单 |
有性能差异吗?
不会。就性能而言,使用Java记录和Lombok注释没有显著差异。两者生成的代码一旦编译,在性能特征方面与手写代码没有什么不同。生成的代码由 Java 编译器优化,因此几乎没有性能开销。
结论:
本文表明我们应该使用记录来编写更清晰、更具可读性的代码。记录可以帮助我们减少样板代码,而无需任何第三方库。Lombok 与 IDE 存在一些兼容性问题。
原文地址:https://www.toutiao.com/article/7292202949005148691/