提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
之前看到有人提到了Lombok中的一个注解叫做@toBuilder,感觉有点意思,所以留下这个学习记录。
一、toBuilder简介
lombok的toBuilder功能是什么?
Lombok的toBuilder功能是一种注解,可以在类上使用,以生成一个可以用来创建类实例的构建器。这样可以简化代码,避免编写冗长的构造器或者setter方法。
@toBuilder使用举例
例如,如果你有一个名为Widget的类,你可以在类声明上添加@Builder注解,然后使用Widget.builder()方法来创建一个Widget对象。
Widget widget = Widget.builder()
.name("My Widget")
.id(123)
.build();
这样就不需要编写一个带有所有参数的构造器或者一个空的构造器和多个setter方法。Lombok会为你生成一个包含所有属性的构建器,你可以链式地调用它的方法,然后使用build()方法来得到一个Widget对象。
二、@toBuilder和@Data有什么区别
@toBuilder和@Data是两个不同的Lombok注解,它们有不同的功能和用途。
@toBuilder是用来生成一个构建器的注解,它可以让你方便地创建类的实例。
@Data是一个方便的快捷注解,它包含了@ToString, @EqualsAndHashCode, @Getter / @Setter 和 @RequiredArgsConstructor的功能,它可以为你生成所有简单POJOs或者beans需要的代码,例如所有字段的getter和setter方法,以及合适的toString, equals和hashCode方法。
假设你有一个名为Person的类,它有三个属性:name
, age
和gender
。如果你只使用@Data注解,你的代码可能是这样的:
@Data
public class Person {
private String name;
private int age;
private String gender;
}
这样,Lombok会为你生成所有字段的getter和setter方法,以及toString, equals和hashCode方法。
你可以这样创建一个Person对象:
Person person = new Person();
person.setName("Alice");
person.setAge(20);
person.setGender("Female");
或者这样:
Person person = new Person("Alice", 20, "Female");
但是,如果你使用@toBuilder
注解,你的代码可能是这样的:
@Getter
@Builder
public class Person {
private final String name;
private final int age;
private final String gender;
}
这样,Lombok会为你生成一个构建器,它可以让你链式地设置属性,然后使用build()方法创建一个Person对象。你可以这样创建一个Person对象:
Person person = Person
.builder()
.name("Alice")
.age(20)
.gender("Female")
.build();
这里的字段都是final的,所以你不能再修改它们的值。这样可以保证对象的不可变性,避免一些潜在的错误。
另外,你也不需要提供所有的参数,只需要提供你想要设置的属性即可。例如,如果你只想设置name属性,你可以这样写:
Person person = Person.builder()
.name("Alice")
.build();
这样就不会报错,而是会使用默认值(null或者0)来填充其他属性。这样可以提高代码的灵活性和可读性。
三、后续讨论
我可以同时使用@toBuilder和@Data吗?
答:是的,你可以同时使用@toBuilder和@Data注解,但是你需要注意一些细节。@Data注解会为你生成所有非final字段的setter方法,这可能会和@toBuilder的构建器模式产生冲突。如果你想要使用链式的setter方法,你可以在类上添加@Accessors(chain = true)注解,这样你就可以像这样创建对象和设置字段:
Entity entity = new Entity()
.setName("Name")
.setBalance(10);
entity.setName("newName");
另外,如果你想要使用@Builder注解在类上,你需要在类声明上添加@Getter注解,否则你无法访问类的属性。
@toBuilder注解有什么优势呢?
@toBuilder注解有以下几个优势:
- 它可以让你用一行代码就生成一个完整的构建器,而不需要自己编写构造器或者setter方法。
- 它可以让你在创建对象时只指定你需要的属性,而不需要传入所有的参数。
- 它可以让你创建不可变的对象,因为它只生成final字段的构建器。
- 它可以让你在继承或者抽象类中使用构建器,只需要在子类或者具体类上添加@SuperBuilder注解。
两个注解如何选择?
如果你只是进行简单的增删改查,那么@Data注解可能更适合你,因为它可以让你省去很多代码,而且可以随时修改对象的属性。但是,如果你想要创建不可变的对象,或者在继承或者抽象类中使用构建器,那么@toBuilder注解可能更有用,因为它可以让你更灵活地设置属性,而且可以保证对象的一致性。
更灵活地设置属性以及保证对象一致性指的是什么呢?
@toBuilder注解可以让你像这样链式地设置属性:
Person person = Person.builder()
.name("Alice")
.age(20)
.gender("Female")
.build();
这样可以提高代码的可读性,而且可以让你只设置你想要的属性,而不需要传入所有的参数。
保证对象一致性指的是,如果你使用@toBuilder注解,那么你创建的对象的属性都是final的,也就是说,你不能再修改它们的值。这样可以避免一些潜在的错误,例如多线程环境下对象被意外修改,或者对象被错误地复制。如果你使用@Data注解,那么你创建的对象的属性都是可变的,也就是说,你可以随时修改它们的值。这样可能会导致一些不一致的情况,例如对象的状态和数据库中的数据不同步,或者对象被其他方法修改而影响原来的逻辑。
关于链式调用与一致性
问题描述:我不觉得链式调用是它的优势,因为实际上我用data注解的话,通过添加@Accessors(chain = true)也可以做到,而且也并不需要传入所有的参数。至于保证对象一致性,这确实是可以的,但主要是因为对象属性是final的,这就注定了一致性,我觉得这并不是tobuilder的功劳。
答:
@toBuilder
注解并不是唯一可以实现链式调用和对象一致性的方式,你也可以使用@Data注解配合@Accessors(chain = true)
和final
字段来达到类似的效果。
但是,@toBuilder
注解还有一些其他的优势,例如它可以让你在继承或者抽象类中使用构建器,只需要在子类或者具体类上添加@SuperBuilder
注解。这样可以让你更方便地创建复杂的对象,而不需要自己编写构造器或者setter
方法。另外,@toBuilder
注解也可以让你在已有的对象上创建一个新的构建器,然后修改部分属性,再创建一个新的对象。这样可以让你更灵活地复用对象,而不需要重新设置所有的属性。
总结
本文仅仅简单记录了一下关于@toBuilder
和@Data
注解相关的疑问,为方便理解故而记录下来。若有不同看法,尽情提出。