当前位置:首页 > 数据库

​Java Record可以完全取代Lombok吗?

译者 | 胥磊

审校 | 梁策 孙淑娟

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

Javaimport 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的类是网站模板这样的:

Javaimport 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类是这样的:

Javapublic record Car(String brand, String model, int year)

{

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

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

3.不可变性

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

Javaimport 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,那么得到的会是一个庞大的构造函数(繁多的入参),随之而来的还有多参构造函数所带来的固有的问题(传参易错位,方法重载难判断等)。

Javapublic record DetailedCar(

String brand, String model, int year,

String engineCode, String engineType, String requiredFuel,

String fuelSystem, String maxHorsePower, String maxTorque,

float fuelCapacity) {

}JavaDetailedCar 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,这样在构建时属性就是必需的。如果必需属性缺失设置则会在运行时抛出一个异常,而不是编译时强制抛出异常。

Javaimport 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

译者介绍

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

分享到:

滇ICP备2023006006号-16