Spring Boot之使用lombok优雅的编码基础教程

lombok是一个编译级别的插件,它可以在项目编译的时候生成一些代码。在很多工具类的项目中都有这个功能。比如dagger。
通俗的说,lombok可以通过注解来标示生成getter settter等代码。我们自然可以通过编译器比如IDEA的Generate生成,为啥要用这个?

springboot

说明

在项目开发阶段,一个class的属性是一直变化的,今天可能增加一个字段,明天可能删除一个字段。每次变化都需要修改对应的模板代码。另外,有的class的字段超级多,多到一眼看不完。如果加上模板代码,更难一眼看出来。更有甚者,由于字段太多,想要使用builder来创建。手动创建builder和字段和原来的类夹杂在一起,看起来真的难受。lombok的@Builder即可解决这个问题。

引入

引入就是加入lombok的jar包。

在maven中

直接加入依赖

1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>

在gradle中

这里比较麻烦,需要添加一个编译时生成代码的插件。gradle里有几个这样的插件。但为了简化过程,lombok提供了新插件。

来源:官网github

首先,添加一个plugin

1
2
3
plugins {
id 'io.franzbecker.gradle-lombok' version '1.11'
}

然后,就可以了。还可以配置lombok的版本:

1
2
3
4
lombok { // optional: values below are the defaults
version = "1.16.20"
sha256 = ""
}

IntelIJ IDEA 插件

在IDEA里使用需要添加一个插件。在插件里搜索lombok,安装,重启。
img

IDEA里需要在设置中启用annotation processors。

img

如果升级了InteliJ IDEA, 可能出现lombok不能用了,右键更新lombok plugin,重启即可。

基本用法

测试代码: https://github.com/Ryan-Miao/someTest/tree/master/src/main/java/com/test/lombok

Geter Setter

最简单的,最常用的,最直观的使用就是getter setter方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.test.lombok;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

import java.util.Date;

/**
* Created by Ryan Miao on 1/18/18.
*/
public class GetterSetterExample {
/**
* Age of the person. Water is wet.
*
* @param age New value for this person's age. Sky is blue.
* @return The current value of this person's age. Circles are round.
*/
@Getter
@Setter
private int age = 10;

@Getter
@Setter
private boolean active;

@Getter
@Setter
private Boolean none;

@Getter
@Setter
private Date date;

/**
* Name of the person.
* -- SETTER --
* Changes the name of this person.
*
* @param name The new value.
*/
@Setter(AccessLevel.PROTECTED) private String name;

@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}

public static void main(String[] args) {
GetterSetterExample example = new GetterSetterExample();
example.setActive(true);
example.setAge(123);
example.setDate(new Date());
example.setName("abc");
example.setNone(false);

Date date = example.getDate();
Boolean none = example.getNone();
boolean active = example.isActive();

}
}

简单使用没有问题,深入一点可以看到有些特殊设定。比如javadoc.

  1. Getter声明创建getter方法;
  2. Setter声明创建setter方法;
  3. @Setter(AccessLevel.PROTECTED)可以添加参数,指定权限为私有;
  4. Attention!关于boolean的set前缀都是set,但getter不同,小写的boolean,即基本类型,前缀是is; Boolean,即包装类型,前缀是get

编译后的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.test.lombok;

import java.util.Date;

public class GetterSetterExample {
private int age = 10;
private boolean active;
private Boolean none;
private Date date;
private String name;

public GetterSetterExample() {
}

public String toString() {
return String.format("%s (age: %d)", this.name, this.age);
}

public static void main(String[] args) {
GetterSetterExample example = new GetterSetterExample();
example.setActive(true);
example.setAge(123);
example.setDate(new Date());
example.setName("abc");
example.setNone(false);
Date date = example.getDate();
Boolean none = example.getNone();
boolean active = example.isActive();
}

public int getAge() {
return this.age;
}

public void setAge(int age) {
this.age = age;
}

public boolean isActive() {
return this.active;
}

public void setActive(boolean active) {
this.active = active;
}

public Boolean getNone() {
return this.none;
}

public void setNone(Boolean none) {
this.none = none;
}

public Date getDate() {
return this.date;
}

public void setDate(Date date) {
this.date = date;
}

protected void setName(String name) {
this.name = name;
}
}

ToString

虽然ToString在生产环境貌似没什么卵用。但是,很多情况下,我们还是需要这个的。因为记log。不想每次看log的时候是一串@地址,那就好好把toString()加上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.test.lombok;

import lombok.Setter;
import lombok.ToString;


/**
* Created by Ryan Miao on 1/18/18.
*/
@Setter
@ToString(exclude="id")
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;


@ToString(callSuper=true, includeFieldNames=true)
public static class Square extends Shape {
private final int width, height;

public Square(int width, int height) {
this.width = width;
this.height = height;
}
}

@ToString
public static class Shape {
private int color;

}

public static void main(String[] args) {
final ToStringExample example = new ToStringExample();
example.setId(1);
example.setName("abc");
example.setTags(new String[]{"a","b","c"});

final Shape shape = new Square(1,2);
example.setShape(shape);

System.out.println(example.toString());
}
}

1.@ToString最简单使用即可

打印结果如下:

ToStringExample(name=abc, shape=ToStringExample.Square(super=ToStringExample.Shape(color=0), width=1, height=2), tags=[a, b, c])

编译后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.test.lombok;

import java.util.Arrays;

public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private ToStringExample.Shape shape = new ToStringExample.Square(5, 10);
private String[] tags;
private int id;

public ToStringExample() {
}

public static void main(String[] args) {
ToStringExample example = new ToStringExample();
example.setId(1);
example.setName("abc");
example.setTags(new String[]{"a", "b", "c"});
ToStringExample.Shape shape = new ToStringExample.Square(1, 2);
example.setShape(shape);
System.out.println(example.toString());
}

public void setName(String name) {
this.name = name;
}

public void setShape(ToStringExample.Shape shape) {
this.shape = shape;
}

public void setTags(String[] tags) {
this.tags = tags;
}

public void setId(int id) {
this.id = id;
}

public String toString() {
return "ToStringExample(name=" + this.name + ", shape=" + this.shape + ", tags=" + Arrays.deepToString(this.tags) + ")";
}

public static class Shape {
private int color;

public Shape() {
}

public String toString() {
return "ToStringExample.Shape(color=" + this.color + ")";
}
}

public static class Square extends ToStringExample.Shape {
private final int width;
private final int height;

public Square(int width, int height) {
this.width = width;
this.height = height;
}

public String toString() {
return "ToStringExample.Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
}
}
}

@EqualsAndHashCode

equals()和hashCode()在Java中有着举足轻重的基地作用,虽然通常很少关注。但是,这个必须不可省。不知道有几个可以手写出来的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.test.lombok;

import lombok.EqualsAndHashCode;

/**
* Created by Ryan Miao on 1/18/18.
*/
@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private ToStringExample.Shape shape = new Square(5, 10);
private String[] tags;
private int id;

public String getName() {
return this.name;
}

@EqualsAndHashCode(callSuper=true)
public static class Square extends ToStringExample.Shape {
private final int width, height;

public Square(int width, int height) {
this.width = width;
this.height = height;
}
}

public static void main(String[] args) {
EqualsAndHashCodeExample example = new EqualsAndHashCodeExample();
EqualsAndHashCodeExample example1 = new EqualsAndHashCodeExample();
boolean equals = example.equals(example1);
boolean b = example.canEqual(example);
int i = example.hashCode();
}
}

编译后的结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.test.lombok;

import com.test.lombok.ToStringExample.Shape;
import java.util.Arrays;

public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new EqualsAndHashCodeExample.Square(5, 10);
private String[] tags;
private int id;

public EqualsAndHashCodeExample() {
}

public String getName() {
return this.name;
}

public static void main(String[] args) {
EqualsAndHashCodeExample example = new EqualsAndHashCodeExample();
EqualsAndHashCodeExample example1 = new EqualsAndHashCodeExample();
example.equals(example1);
boolean b = example.canEqual(example);
int i = example.hashCode();
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof EqualsAndHashCodeExample)) {
return false;
} else {
EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o;
if (!other.canEqual(this)) {
return false;
} else {
label31: {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
break label31;
}
} else if (this$name.equals(other$name)) {
break label31;
}

return false;
}

if (Double.compare(this.score, other.score) != 0) {
return false;
} else {
return Arrays.deepEquals(this.tags, other.tags);
}
}
}
}

protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeExample;
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
long $score = Double.doubleToLongBits(this.score);
result = result * 59 + (int)($score >>> 32 ^ $score);
result = result * 59 + Arrays.deepHashCode(this.tags);
return result;
}

public static class Square extends Shape {
private final int width;
private final int height;

public Square(int width, int height) {
this.width = width;
this.height = height;
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof EqualsAndHashCodeExample.Square)) {
return false;
} else {
EqualsAndHashCodeExample.Square other = (EqualsAndHashCodeExample.Square)o;
if (!other.canEqual(this)) {
return false;
} else if (!super.equals(o)) {
return false;
} else if (this.width != other.width) {
return false;
} else {
return this.height == other.height;
}
}
}

protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeExample.Square;
}

public int hashCode() {
int PRIME = true;
int result = super.hashCode();
result = result * 59 + this.width;
result = result * 59 + this.height;
return result;
}
}
}

构造函数@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

Java中class的一切起源于构造器。大家最喜欢的还是构造函数创建对象。这里有一点比较坑的是无参构造函数。当你自己添加一个带有参数的构造函数后,无参构造函数则别隐藏。通常也没啥问题,但当你使用jackson反序列化对象的时候就被恶心到了。jackson通过无参构造函数创建对象。因此,当你考虑这个class会用来序列化为json的时候,即必须手动添加一个无参数构造函数。

@NoArgsConstructor

当你想要创建一个valueobject,DDD中的值对象,要求实现Immutable,那么无参数构造器就不合适了。@NoArgsConstructor会生成一个空的构造器。如果你设置了final field,那么编译会报错。如果你强制执行创建无参数构造器。即,@NoArgsConstructor(force = true),那么final的field会初始化为0/false/null。通常适合与@Data集成。

1
2
3
4
@NoArgsConstructor
public static class NoArgsExample {
@NonNull private String field;
}
  • NonNull被忽略了

最终生成代码如下:

1
2
3
4
5
6
7
public static class NoArgsExample {
@NonNull
private String field;

public NoArgsExample() {
}
}

对于final的字段,我认为我不会用空构造器来做这件事。所以,感觉这个参数force=true不要也罢,鸡肋。

@RequiredArgsConstructor

一个class可以有很多属性,但你可能只关心其中的几个字段,那么可以使用@RequiredArgsConstructor@NonNull将标注这个字段不应为null,初始化的时候会检查是否为空,否则抛出NullPointException。在上面的无参构造函数中被忽略了。那么,对于关注的字段标注@NonNull, @RequiredArgsConstructor则会生成带有这些字段的构造器。

1
2
3
4
5
6
7
8
9
@RequiredArgsConstructor
public class RequiredArgsExample {
@NonNull private String field;
private Date date;
private Integer integer;
private int i;
private boolean b;
private Boolean aBoolean;
}

最终生成结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class RequiredArgsExample {
@NonNull
private String field;
private Date date;
private Integer integer;
private int i;
private boolean b;
private Boolean aBoolean;

public RequiredArgsExample(@NonNull String field) {
if (field == null) {
throw new NullPointerException("field");
} else {
this.field = field;
}
}
}

只有@NonNull会生成构造器。其他默认,Java的class初始化默认为null.false,0.

lombok提供了另一种初始化做法,静态初始化。即私有构造器,使用静态方法创建对象。这种做法看起来简单,但通常用的不多。因为静态初始化的东西很难mock,对测试不够友好。

1
2
3
4
5
6
7
8
9
@RequiredArgsConstructor(staticName = "of")
public static class RequiredArgsStaticExample {
@NonNull private String field;
private Date date;
private Integer integer;
private int i;
private boolean b;
private Boolean aBoolean;
}

最终生成代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ConstructorExample<T> {
private int x;
private int y;
@NonNull
private T description;
private ConstructorExample(@NonNull T description) {
if (description == null) {
throw new NullPointerException("description");
} else {
this.description = description;
}
}
public static <T> ConstructorExample<T> of(@NonNull T description) {
return new ConstructorExample(description);
}
}

@AllArgsConstructor

想要初始化所有字段。

1
2
3
4
5
6
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
private int x, y;
@NonNull
private T description;
}

最终生成代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ConstructorExample<T> {
private int x;
private int y;
@NonNull
private T description;
protected ConstructorExample(int x, int y, @NonNull T description) {
if (description == null) {
throw new NullPointerException("description");
} else {
this.x = x;
this.y = y;
this.description = description;
}
}
}

必用项@Data

1
@Data`是一个集合体。包含`Getter`,`Setter`,`RequiredArgsConstructor`,`ToString`,`EqualsAndHashCode

不可变对象valueobject @Value

这个看起来很美好,就是可以帮忙生成一个不可变对象。对于所有的字段都将生成final的。但我感觉有点失控。注解的优势应该是所见即所得,可以通过字面量来传递消息。而@Value字段给字段加final会让人困惑,因为这更改了我们的定义。当我想声明一个Immutable对象的时候,我会显示的给字段加一个限定final。

@Data@Value是一个集合体。包含Getter,AllArgsConstructor,ToString,EqualsAndHashCode

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Created by Ryan Miao on 1/18/18.
*/
@Value
public class Room {
@NonNull
private String id;
private String name;
private boolean active;
private Date createTime;

}

编译后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public final class Room {
@NonNull
private final String id;
private final String name;
private final boolean active;
private final Date createTime;

public Room(@NonNull String id, String name, boolean active, Date createTime) {
if (id == null) {
throw new NullPointerException("id");
} else {
this.id = id;
this.name = name;
this.active = active;
this.createTime = createTime;
}
}

@NonNull
public String getId() {
return this.id;
}

public String getName() {
return this.name;
}

public boolean isActive() {
return this.active;
}

public Date getCreateTime() {
return this.createTime;
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Room)) {
return false;
} else {
Room other = (Room)o;
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id != null) {
return false;
}
} else if (!this$id.equals(other$id)) {
return false;
}

label41: {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
break label41;
}
} else if (this$name.equals(other$name)) {
break label41;
}

return false;
}

if (this.isActive() != other.isActive()) {
return false;
} else {
Object this$createTime = this.getCreateTime();
Object other$createTime = other.getCreateTime();
if (this$createTime == null) {
if (other$createTime != null) {
return false;
}
} else if (!this$createTime.equals(other$createTime)) {
return false;
}

return true;
}
}
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + (this.isActive() ? 79 : 97);
Object $createTime = this.getCreateTime();
result = result * 59 + ($createTime == null ? 43 : $createTime.hashCode());
return result;
}

public String toString() {
return "Room(id=" + this.getId() + ", name=" + this.getName() + ", active=" + this.isActive() + ", createTime=" + this.getCreateTime() + ")";
}
}

最喜欢的项 @Builder

对于喜欢builder模式的人来说,声明式简化对象创建流程让一切看得美好。但是,手动复制字段,手动创建方法很让人不喜。@Builder解决了刚需。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Created by Ryan Miao on 1/18/18.
*/
@Data
@Builder(toBuilder = true)
public class Room {
@NonNull
private String id;
private String name;
private boolean active;
private Date createTime;
@Singular
private Set<String> occupations;

public static void main(String[] args) {
Room room = Room.builder().active(true)
.name("name")
.id("id")
.createTime(new Date())
.occupation("1")
.occupation("2")
.build();

Assert.assertEquals(2, room.getOccupations().size());

}
}

这才是我们想要的建造者。对应生成的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.test.lombok;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import lombok.NonNull;
import org.junit.Assert;

public class Room {
@NonNull
private String id;
private String name;
private boolean active;
private Date createTime;
private Set<String> occupations;

public static void main(String[] args) {
Room room = builder().active(true).name("name").id("id").createTime(new Date()).occupation("1").occupation("2").build();
Assert.assertEquals(2L, (long)room.getOccupations().size());
}

Room(@NonNull String id, String name, boolean active, Date createTime, Set<String> occupations) {
if (id == null) {
throw new NullPointerException("id");
} else {
this.id = id;
this.name = name;
this.active = active;
this.createTime = createTime;
this.occupations = occupations;
}
}

public static Room.RoomBuilder builder() {
return new Room.RoomBuilder();
}

public Room.RoomBuilder toBuilder() {
return (new Room.RoomBuilder()).id(this.id).name(this.name).active(this.active).createTime(this.createTime).occupations(this.occupations);
}

@NonNull
public String getId() {
return this.id;
}

public String getName() {
return this.name;
}

public boolean isActive() {
return this.active;
}

public Date getCreateTime() {
return this.createTime;
}

public Set<String> getOccupations() {
return this.occupations;
}

public void setId(@NonNull String id) {
if (id == null) {
throw new NullPointerException("id");
} else {
this.id = id;
}
}

public void setName(String name) {
this.name = name;
}

public void setActive(boolean active) {
this.active = active;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

public void setOccupations(Set<String> occupations) {
this.occupations = occupations;
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Room)) {
return false;
} else {
Room other = (Room)o;
if (!other.canEqual(this)) {
return false;
} else {
label63: {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id == null) {
break label63;
}
} else if (this$id.equals(other$id)) {
break label63;
}

return false;
}

Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}

if (this.isActive() != other.isActive()) {
return false;
} else {
Object this$createTime = this.getCreateTime();
Object other$createTime = other.getCreateTime();
if (this$createTime == null) {
if (other$createTime != null) {
return false;
}
} else if (!this$createTime.equals(other$createTime)) {
return false;
}

Object this$occupations = this.getOccupations();
Object other$occupations = other.getOccupations();
if (this$occupations == null) {
if (other$occupations != null) {
return false;
}
} else if (!this$occupations.equals(other$occupations)) {
return false;
}

return true;
}
}
}
}

protected boolean canEqual(Object other) {
return other instanceof Room;
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + (this.isActive() ? 79 : 97);
Object $createTime = this.getCreateTime();
result = result * 59 + ($createTime == null ? 43 : $createTime.hashCode());
Object $occupations = this.getOccupations();
result = result * 59 + ($occupations == null ? 43 : $occupations.hashCode());
return result;
}

public String toString() {
return "Room(id=" + this.getId() + ", name=" + this.getName() + ", active=" + this.isActive() + ", createTime=" + this.getCreateTime() + ", occupations=" + this.getOccupations() + ")";
}

public static class RoomBuilder {
private String id;
private String name;
private boolean active;
private Date createTime;
private ArrayList<String> occupations;

RoomBuilder() {
}

public Room.RoomBuilder id(String id) {
this.id = id;
return this;
}

public Room.RoomBuilder name(String name) {
this.name = name;
return this;
}

public Room.RoomBuilder active(boolean active) {
this.active = active;
return this;
}

public Room.RoomBuilder createTime(Date createTime) {
this.createTime = createTime;
return this;
}

public Room.RoomBuilder occupation(String occupation) {
if (this.occupations == null) {
this.occupations = new ArrayList();
}

this.occupations.add(occupation);
return this;
}

public Room.RoomBuilder occupations(Collection<? extends String> occupations) {
if (this.occupations == null) {
this.occupations = new ArrayList();
}

this.occupations.addAll(occupations);
return this;
}

public Room.RoomBuilder clearOccupations() {
if (this.occupations != null) {
this.occupations.clear();
}

return this;
}

public Room build() {
Set occupations;
switch(this.occupations == null ? 0 : this.occupations.size()) {
case 0:
occupations = Collections.emptySet();
break;
case 1:
occupations = Collections.singleton(this.occupations.get(0));
break;
default:
Set<String> occupations = new LinkedHashSet(this.occupations.size() < 1073741824 ? 1 + this.occupations.size() + (this.occupations.size() - 3) / 3 : 2147483647);
occupations.addAll(this.occupations);
occupations = Collections.unmodifiableSet(occupations);
}

return new Room(this.id, this.name, this.active, this.createTime, occupations);
}

public String toString() {
return "Room.RoomBuilder(id=" + this.id + ", name=" + this.name + ", active=" + this.active + ", createTime=" + this.createTime + ", occupations=" + this.occupations + ")";
}
}
}

总结

lombok还提供了其他几个注解,以及还有好多内置的参数没有讲解。但是,根据2-8原理,我们根本不需要。上面这几个足够了。更多的注解只会增加理解阅读难度。

参考

https://projectlombok.org/features/all
http://kriszhang.com/lombok/

个人微信公众号技术交流QQ群
文章目录
  1. 1. 说明
  2. 2. 引入
    1. 2.1. 在maven中
    2. 2.2. 在gradle中
    3. 2.3. IntelIJ IDEA 插件
  3. 3. 基本用法
    1. 3.1. Geter Setter
    2. 3.2. ToString
    3. 3.3. @EqualsAndHashCode
    4. 3.4. 构造函数@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor
      1. 3.4.1. @NoArgsConstructor
      2. 3.4.2. @RequiredArgsConstructor
      3. 3.4.3. @AllArgsConstructor
    5. 3.5. 必用项@Data
    6. 3.6. 不可变对象valueobject @Value
    7. 3.7. 最喜欢的项 @Builder
  4. 4. 总结
  5. 5. 参考