Lombok中的@Builder用法
# 详解Lombok中的@Builder用法
hello_world!2020-03-04 14:58:35
3766[
收藏
16
]()分类专栏:[lombok](https://blog.csdn.net/djrm11/category_9772102.html)[版权]()[https://www.jianshu.com/p/d08e255312f9](https://www.jianshu.com/p/d08e255312f9)
简述:Builder 使用创建者模式又叫建造者模式。简单来说,就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程。
基础使用
@Builder
注释为你的类生成相对略微复杂的构建器API。@Builder
可以让你以下面显示的那样调用你的代码,来初始化你的实例对象:
```
- 1Student.builder
- 2.sno”001”
- 3.sname”admin”
- 4.sage18
- 5.sphone”110”
- 6.build
`@Builder`可以放在类,构造函数或方法上。 虽然放在类上和放在构造函数上这两种模式是最常见的用例,但`@Builder`最容易用放在方法的用例来解释。
### 那么@Builder内部帮我们做了什么?
1. 创建一个名为`ThisClassBuilder`的内部静态类,并具有和实体类形同的属性(称为构建器)。
1. 在构建器中:对于目标类中的所有的属性和未初始化的`final`字段,都会在构建器中创建对应属性。
1. 在构建器中:创建一个无参的`default`构造函数。
1. 在构建器中:对于实体类中的每个参数,都会对应创建类似于`setter`的方法,只不过方法名与该参数名相同。 并且返回值是构建器本身(便于链式调用),如上例所示。
1. 在构建器中:一个`build()`方法,调用此方法,就会根据设置的值进行创建实体对象。
1. 在构建器中:同时也会生成一个`toString()`方法。
1. 在实体类中:会创建一个`builder()`方法,它的目的是用来创建构建器。
>
> 说这么多,不如让我们通过下面这个例子来理解:
>
- 1@Builder
- 2publicclass User
- 3privatefinal200
- 4private
- 5private
- 6
- 7
- 8// 编译后:
- 9publicclass User
- 10private
- 11private
- 12
- 13thisthis
- 14
- 15public
- 16return
- 17
- 18
- 19publicclass UserBuilder
- 20private
- 21private
- 22
- 23
- 24public
- 25this
- 26returnthis
- 27
- 28public
- 29this
- 30returnthis
- 31
- 32public
- 33returnthisthis
- 34
- 35public
- 36return”User.UserBuilder(username=”this”, password=”this”)”
- 37
- 38
- 39
### 组合用法
1. @Builder中使用 @Singular 注释集合<br />`@Builder`也可以为集合类型的参数或字段生成一种特殊的方法。 它采用修改列表中一个元素而不是整个列表的方式,可以是增加一个元素,也可以是删除一个元素。<br />
- 1Student.builder
- 2.sno”001”
- 3.sname”admin”
- 4.sage18
- 5.sphone”110”.sphone”112”
- 6.build
这样就可以轻松地将`List <String>`字段中包含2个字符串。 但是想要这样来操作集合,你需要使用`@Singular`来注释字段或参数。<br />在使用`@Singular`注释注释一个集合字段(使用`@Builder`注释类),`lombok`会将该构建器节点视为一个集合,并生成两个`adder`方法而不是`setter`方法。
- 一个向集合添加单个元素
- 一个将另一个集合的所有元素添加到集合中
将不生成仅设置集合(替换已添加的任何内容)的setter。 还生成了clear方法。 这些singular构建器相对而言是有些复杂的,主要是来保证以下特性:
1. 在调用`build()`时,生成的集合将是不可变的。
1. 在调用`build()`之后调用其中一个`adder`方法或`clear`方法不会修改任何已经生成的对象。如果对集合修改之后,再调用`build()`,则会创建一个基于上一个对象创建的对象实体。
1. 生成的集合将被压缩到最小的可行格式,同时保持高效。
`@Singular`只能应用于`lombok`已知的集合类型。目前,支持的类型有:
- java.util:
- `Iterable`, `Collection`, 和`List` (一般情况下,由压缩的不可修改的`ArrayList`支持).
- `Set`, `SortedSet`, and `NavigableSet` (一般情况下,生成可变大小不可修改的`HashSet`或者`TreeSet`).
- `Map`, `SortedMap`, and `NavigableMap` (一般情况下,生成可变大小不可修改的`HashMap`或者`TreeMap`).
- Guava’s com.google.common.collect:
- `ImmutableCollection` and `ImmutableList`
- `ImmutableSet` and `ImmutableSortedSet`
- `ImmutableMap`, `ImmutableBiMap`, and `ImmutableSortedMap`
- `ImmutableTable`
>
> 来看看使用了@Singular注解之后的编译情况:
>
- 1@Builder
- 2publicclass User
- 3privatefinal
- 4privatefinal”123456”
- 5private
- 6private
- 7@Singular
- 8private
- 9
- 10
- 11// 编译后:
- 12publicclass User
- 13privatefinal
- 14privatefinal”123456”
- 15private
- 16private
- 17private
- 18
- 19thisthis
- 20thisthis
- 21
- 22
- 23publicreturn
- 24
- 25publicclass UserBuilder
- 26private
- 27private
- 28private
- 29private
- 30
- 31publicthisreturnthis
- 32publicthisreturnthis
- 33publicthisreturnthis
- 34
- 35public
- 36ifthisnull
- 37this
- 38
- 39this
- 40returnthis
- 41
- 42
- 43public
- 44ifthisnull
- 45this
- 46
- 47this
- 48returnthis
- 49
- 50
- 51public
- 52ifthisnull
- 53this
- 54
- 55returnthis
- 56
- 57
- 58public
- 59
- 60thisnull0this
- 610
- 62
- 63break
- 641
- 65thisget0
- 66break
- 67default
- 68this
- 69
- 70returnthisthisthis
- 71
- 72public
- 73return”User.UserBuilder(id=”this”, username=”this”, password=”this”, hobbies=”this”)”
- 74
- 75
- 76
其实,lombok的创作者还是很用心的,在进行build()来创建实例对象时,<br /> 并没有直接使用`Collections.unmodifiableList(Collection)`此方法来床架实例,而是分为三种情况。
- 第一种,当集合中没有元素时,创建一个空list
- 第二种情况,当集合中存在一个元素时,创建一个不可变的单元素list
- 第三种情况,根据当前集合的元素数量创建对应合适大小的list
当然我们看编译生成的代码,创建了三个关于集合操作的方法:
- `hobby(String hobby)`:向集合中添加一个元素
- `hobbies(Collection<? extends String> hobbies)`:添加一个集合所有的元素
- `clearHobbies()`:清空当前集合数据
2. @Singular 注解配置value属性
>
> 我们先来看看 @Singular 注解的详情:
>
- 1@Target({FIELD, PARAMETER})
- 2@Retention(SOURCE)
- 3public@interface
- 4// 修改添加集合元素的方法名
- 5default””
- 6
- 测试如何使用注解属性`value`
- 1
- 2publicclass User
- 3privatefinalInteger
- 4privatefinalString”123456”
- 5privateString
- 6privateString
- 7”testHobbies”
- 8privateListString
- 9
- 10
- 11// 测试类
- 12publicclass BuilderTest
- 13publicstaticvoidString
- 14
- 15”reading”
- 16”eat”
- 171
- 18”admin”
- 19”admin”
- 20
- 21
- 22
- 23
说明,当我们使用了注解属性`value`之后,我们在使用添加集合元素时的方法名发生相应的改变。但是,同时生成的添加整个集合的方法名发生改变了吗?我们再来看看编译后的代码:<br />
- 1
- 2publicclass User
- 3// 省略部分代码,只看关键部分
- 4publicclass UserBuilder
- 5public
- 6ifthisnull
- 7this
- 8
- 9this
- 10returnthis
- 11
- 12
- 13public
- 14ifthisnull
- 15this
- 16
- 17this
- 18returnthis
- 19
- 20
- 21public
- 22ifthisnull
- 23this
- 24
- 25returnthis
- 26
- 27
- 28
可以看到,只有添加一个元素的方法名发生了改变。<br />3. @Builder.Default 的使用<br />比如有这样一个实体类:<br />
- 1@Builder
- 2@ToString
- 3publicclass User {
- 4@Builder
- 5privatefinal
- 6private
- 7private
- 8@Builder
- 9privatelong
- 10
在类中我在`id`和`insertTime`上都添加注解`@Builder.Default`,当我在使用这个实体对象时,我就不需要在为这两个字段进行初始化值,如下面这样:<br />
- 1publicclassBuilderTest
- 2public static void main(String[] args)
- 3
- 4”admin”
- 5”admin”
- 6
- 7out
- 8
- 9
- 10
- 11// 输出内容:
- 12416219e1-43f-9f1546869309868
`lombok`在实例化对象时就为我们初始化了这两个字段值。<br />当然,你如果再对这两个字段进行设值的话,那么默认定义的值将会被覆盖掉,如下面这样:<br />
- 1publicclassBuilderTest
- 2public static void main(String[] args)
- 3
- 4”admin”
- 5”admin”
- 6”admin”
- 7
- 8out
- 9
- 10
- 11// 输出内容
- 121546869642151
4. @Builder 详细配置<br />下面我们再来详细看看`@Builder`这个注解类地详细实现:<br />
- 1@Target({TYPE, METHOD, CONSTRUCTOR})
- 2@Retention(SOURCE)
- 3public@interface
- 4// 如果@Builder注解在类上,可以使用 @Builder.Default指定初始化表达式
- 5@Target(FIELD)
- 6@Retention(SOURCE)
- 7public@interface
- 8// 指定实体类中创建 Builder 的方法的名称,默认为: builder (个人觉得没必要修改)
- 9String builderMethodName() default “builder”
- 10// 指定 Builder 中用来构件实体类的方法的名称,默认为:build (个人觉得没必要修改)
- 11String buildMethodName() default “build”
- 12// 指定创建的建造者类的名称,默认为:实体类名+Builder
- 13String builderClassName() default “”
- 14// 使用toBuilder可以实现以一个实例为基础继续创建一个对象。(也就是重用原来对象的值)
- 15boolean toBuilder() default false
- 16
- 17@Target({FIELD, PARAMETER})
- 18@Retention(SOURCE)
- 19public@interface
- 20// 告诉lombok使用表达式获取值
- 21String field() default “”
- 22// 告诉lombok使用表达式获取值
- 23String method() default “”
- 24
- 25boolean isStatic() default false
- 26
- 27
以上注解属性,我只测试一个比较常用的`toBuilder`,因为我们在对实体对象进行操作时,往往会存在对某些实体对象的某个字段进行二次赋值,这个时候就会用到这一属性。但是,这会创建一个新的对象,而不是原来的对象,原来的对象属性是不可变的,除非你自己想要给这个实体类再添加上`@Data`或者`@setter`方法。下面就来测试一下:<br />
- 1true
- 2
- 3publicclassUser
- 4private
- 5private
- 6
- 7// 测试类
- 8publicclassBuilderTest
- 9public static void main(String[] args)
- 10
- 11”admin”
- 12”admin”
- 13
- 14out
- 15
- 16”admin2”
- 17// 验证user2是否是基于user1的现有属性创建的
- 18out
- 19// 验证对象是否是同一对象
- 20out
- 21
- 22
- 23// 输出内容
- 24
- 25
- 26false
5. @Builder 全局配置<br />
- 1# 是否禁止使用@Builder
- 2lombok.builder.flagUsage
- 3# 是否使用Guaua
- 4lombok.singular.useGuavatruefalsefalse
- 5# 是否自动使用singular,默认是使用
- 6lombok.singular.autotruefalsetrue
```
- 总的来说
@Builder
还是很好用的。文章参考自:https://blog.csdn.net/weixin_41540822/article/details/86606562
作者:虹猫日志
链接:https://www.jianshu.com/p/d08e255312f9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。