​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-07-20 08:16:54

Lombokjava工具

2024-01-11 13:21:53

开发代码

2023-09-21 15:05:12

ChatGPT搜索引擎

2018-10-19 11:19:32

云存储现场存储云服务

2010-03-22 09:49:01

智能交换机

2020-08-04 10:03:03

Python开发语言

2019-01-04 09:30:05

人工智能同传翻译深度学习

2019-08-01 14:00:21

2020-11-07 16:25:50

人工智能技术IT

2022-04-02 11:28:37

元宇宙远程办公

2009-01-16 15:33:10

EMCCLARiiON存储市场

2019-02-26 13:53:07

PythonJava编程语言

2018-05-04 09:25:47

2022-11-29 07:33:15

JavaLombokRecord

2017-10-10 09:58:44

人工智能 应用 临床

2023-03-28 07:55:22

固态硬盘机械硬盘芯片

2015-10-15 12:00:44

2009-07-10 15:37:08

ScalaFan函数式编程

2018-03-19 16:05:51

前端程序员

2022-06-15 12:48:14

WebAssemblDockerKubernetes
点赞
收藏

51CTO技术栈公众号