社区编辑申请
注册/登录
​Java Record可以完全取代Lombok吗? 译文
开发 前端
本文将探讨下 JDK14 后新增的 Record 类型,作为数据载体的这一新类型是否可以完全地取代 Lombok。

译者 | 胥磊

审校 | 梁策 孙淑娟

很长时间以来,Java 都因其冗长而受到一些开发者的诟病。哪怕是最热衷 Java 的开发者或许也不得不承认,声明一个只有两个属性的 bean 类Java让人觉得有点可笑。因为如果遵循推荐规范,最终不仅添加了 getter 和 setter方法,还要添加toString, hashcode 和 equals 方法的重写,最终大块的样板文件式的代码逼得开发者想放弃Java语言。

Java

import java.util.Objects;
public class Car {
private String brand;
private String model;
private int year;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", model='" + model + '\'' +
", year=" + year +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return year == car.year && Objects.equals(brand, car.brand) && Objects.equals(model, car.model);
}
@Override
public int hashCode() {
return Objects.hash(brand, model, year);
}
}

幸运的是,Lombok的横空出世大大减轻了Java开发者的痛苦。但自从有了与其作用相似的Java Record类型,有人可能会问:Record是否可以全面取代Lombok呢?

1.Lombok是什么?

Lombok是一个与开发环境高度集成的 Java 类库(当然也可以看成一种语法糖),通过注解改进(spice)代码,它在 Java 社区中被广泛接受和使用。

使用了Lombok后,我们新建一个名为Car的类是这样的:

Java

import lombok.Data;
@Data
public class Car {
private String brand;
private String model;
private int year;
}

代码更加简洁,同时也不会影响之前版本的任何功能。

2.Java Record是什么?

定义的每一个Java Record类型可以简单地看做是值对象(Value Object)模式的实现。它本质还是一个 Java 类,其中所有的属性都是final的。所以在创建对象时所有类属性都需要传递。Java Record是在 Java 14中引入的,它将持续改进,提升类设计。

通过Record新建Car类是这样的:

Java

public record Car(String brand, String model, int year) 
{

与前一个版本对比,改进非常明显。

下文将分析Lombok的一些特性,并通过和Record进行比较来评估是否可以永久让Lombok退出历史舞台。

3.不可变性

Record默认情况下是不可变的,这意味着所有的类属性都被隐式的声明为 final。我们通常认为Record和值对象(Value Objects)很相似,但是它们没有 setter 方法,所有的值都需要在构造函数中传递。Lombok可以使用@Value 注解达成同样的效果,但也可以使用@Data注解来保持可变性。

Java

import lombok.Value;
@Value
public class Car {
private String brand;
private String model;
private int year;
}

4.Bean公约

Record并不打算遵循 bean的公约,获取对象的方法不使用 getX 的方式命名,同时也不再提供 setter 方法和无参的构造函数。另一方面,Lombok只需使用@Data注解就可以将一个类轻松转换为 JavaBean。

5.Builder

Builder构建器模式是改善对象、创建语法很棒的一种设计模式。Lombok为我们提供了@Builder这个很实用的注解,它帮我们实现了所有样板代码。到目前为止,Java Record 并不打算提供此类实现。

Java

import lombok.Builder;
@Builder
public class Car {
private String brand;
private String model;
private int year;
public static void main(String[] args) {
Car myCamaro = Car.builder()
.brand("Chevrolet")
.model("Camaro")
.year(2022)
.build();
}
}

6.多fields类

Record只对少量fields的类是友好的。但是,如果再向其中添加10个fields,那么得到的会是一个庞大的构造函数(繁多的入参),随之而来的还有多参构造函数所带来的固有的问题(传参易错位,方法重载难判断等)。

Java

public record DetailedCar(
String brand, String model, int year,
String engineCode, String engineType, String requiredFuel,
String fuelSystem, String maxHorsePower, String maxTorque,
float fuelCapacity) {
}

Java

DetailedCar camaroDetailed = new DetailedCar(
"Chevrolet", "Camaro", 2022, "LTG", "Turbocharged",
"Gas I4", "Direct Injection", "275 @ 560", "295 @ 3000-4500",
19.0f);

使用了Lombok,我们就可以决定创建bean类是选择使用 setter来设置对象的状态,还是使用builder这种更简洁的方式来构造实例。唯一需要注意的是,因为其默认不会强制设置所有属性,所以可能使实例处于属性不完整状态。当然@Builder 注解支持我们将类中所有属性标记为@nonNull,这样在构建时属性就是必需的。如果必需属性缺失设置则会在运行时抛出一个异常,而不是编译时强制抛出异常。

Java

import lombok.Builder;
import lombok.NonNull;
@Builder
public class DetailedCar {
@NonNull
private String brand;
@NonNull
private String model;
@NonNull
private int year;
@NonNull
private String engineCode;
@NonNull
private String engineType;
@NonNull
private String requiredFuel;
@NonNull
private String fuelSystem;
@NonNull
private String maxHorsePower;
@NonNull
private String maxTorque;
@NonNull
private float fuelCapacity;
public static void main(String[] args) {
DetailedCar camaroIncomplete = DetailedCar.builder()
.brand("Chevrolet")
.model("Camaro")
.year(2022)
.build();
}
}

输出:

Exception in thread "main" java.lang.NullPointerException: engineCode is marked non-null but is null

7.继承

到目前为止,Java Record类是不支持继承的,所以不能通过扩展其他Record类来创建一个新的Record类,这可能是模型设计的一个限制。尽管如此,我们也要认识到组合优于继承(面向对象设计原则之七)。

Java

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Car extends MotorVehicle {
private String brand;
private String model;
private int year;
}

8.结论

Record是Java的一个极佳的新特性,它正推动代码向更简洁的方向发展,因此应该多多使用。对于提供了众多功能的Lombok,考虑到Java变更的缓慢速度,要在项目中将其彻底取代似乎还为时尚早。

原文链接:https://dzone.com/articles/records-vs-lombok

译者介绍

胥磊,51CTO社区编辑,某头部电商技术副总监,关注Java后端开发,技术管理,架构优化,分布式开发等领域。

责任编辑:武晓燕 来源: 51CTO技术栈
相关推荐

2022-06-05 21:09:47

Python办公自动化

2022-06-01 11:14:42

Java代码技巧

2022-06-27 09:54:38

编程语言JavaC++

2022-06-21 09:26:21

Shell脚本JavaScript

2022-06-13 12:43:13

Java模块

2022-06-02 14:27:05

UI框架JS

2022-06-21 09:02:49

python技巧

2022-06-22 08:02:11

2022-06-23 13:13:36

GitHub开发技巧

2022-06-26 09:55:00

接口自动化项目

2022-06-21 14:22:08

云计算混合云人工智能

2022-06-16 14:07:26

Java代码代码review

2022-05-09 11:52:38

Java卡片服务卡片

2022-06-15 09:54:51

PythonIDELinux

2022-04-28 15:38:42

WebViewJavaUI

2022-06-16 16:08:00

Python初学者IDE

2022-06-10 13:56:42

Java

2022-06-01 09:38:36

KubernetesPod容器

2022-06-17 14:55:25

计算神经网络

2022-05-25 14:02:08

远程办公

同话题下的热门内容

哪个版本的JVM最快?无代码软件发展简史及未来趋势携程基于 GraphQL 的前端 BFF 服务开发实践为什么会存在 1px 问题?怎么解决?一文搞定常考Vue-Router知识点EcmaScript 2022 正式发布,有哪些新特性?一文详解|增长那些事儿远程医疗:优势、前景和现有IT解决方案

编辑推荐

太厉害了,终于有人能把TCP/IP协议讲的明明白白了!牛人5次面试腾讯不成功的经验HBase原理–所有Region切分的细节都在这里了Javascript如何监听页面刷新和关闭事件如何搭建一个HTTPS服务端
我收藏的内容
点赞
收藏

51CTO技术栈公众号