Lombok入门

通过使用Lombok来略去编写私有成员变量的get和set方法。减少了大量的代码冗余。、

使用Maven导入

1
2
3
4
5
6
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>compile</scope>
</dependency>

原理解析

Lombok是一种插件化注解API,是通过添加注解来实现的,然后在javac进行编译的时候,进行处理。

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
public class User {
public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

private Integer id;

private String username;

private String password;
}

编译后的由字节码反编译的代码:

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
public class User {
private Integer id;
private String username;
private String password;

public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

public Integer getId() {
return this.id;
}

public String getUsername() {
return this.username;
}

public String getPassword() {
return this.password;
}

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

public void setUsername(String username) {
this.username = username;
}

public void setPassword(String password) {
this.password = password;
}

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

return false;
}

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

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

return true;
}
}
}

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

public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $username = this.getUsername();
result = result * 59 + ($username == null ? 43 : $username.hashCode());
Object $password = this.getPassword();
result = result * 59 + ($password == null ? 43 : $password.hashCode());
return result;
}

public String toString() {
Integer var10000 = this.getId();
return "User(id=" + var10000 + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ")";
}
}

我们可以看到,Lombok在编译的时候帮助我们添加了很多有用的方法,如get,set,equals,tostring等。

具体标签

@Setter 和 @Getter

可以将这两个标签添加在类前,表示给这个类的所有非静态成员变量添加(set / get)方法。

同时,声明为final的成员变量,Lombok不会为它生成Setter方法。

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Setter
public class User {
public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

private Integer id;

private String username;

private String password;
}

编译后的由字节码反编译的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class User {
private Integer id;
private String username;
private String password;

public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

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

public void setUsername(String username) {
this.username = username;
}

public void setPassword(String password) {
this.password = password;
}
}

同时可以在标签后添加权限控制,例如:

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Setter(AccessLevel.PUBLIC)
@Getter(AccessLevel.PROTECTED)
public class User {
public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

private Integer id;

private String username;

private String password;
}

编译后的由字节码反编译的代码:

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
public class User {
private Integer id;
private String username;
private String password;

public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

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

public void setUsername(String username) {
this.username = username;
}

public void setPassword(String password) {
this.password = password;
}

protected Integer getId() {
return this.id;
}

protected String getUsername() {
return this.username;
}

protected String getPassword() {
return this.password;
}
}

可以看到,经过我们的设置,所有的get方法的访问权限都为protected,所有的set方法的访问权限都为public。

同时,该标签还可以添加在成员变量之前:

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class User {
public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}
@Getter
private Integer id;

@Getter
@Setter
private String username;

@Getter
private String password;
}

编译后的由字节码反编译的代码:

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
public class User {
private Integer id;
private String username;
private String password;

public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

public Integer getId() {
return this.id;
}

public String getUsername() {
return this.username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return this.password;
}
}

如果在静态成员变量前添加标签,生成的getter和setter方法都将是静态的。

@Accessors

通过Accessors标签来设置@Getter和@Setter的样式。

@Accessors(chain = true)

该类的Setter方法会返回this(即该类的实例),所以我们就可以链式调用这些方法,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public User setId(Integer id) {
this.id = id;
return this;
}

public User setUsername(String username) {
this.username = username;
return this;
}

public User setPassword(String password) {
this.password = password;
return this;
}

在使用时,可以这样:

1
2
3
4
public void Usertry() {
User user = new User();
user.setUsername("abaaba").setPassword("123").setId(1);
}

@Accessors(fluent = true)

会通过多态,直接将Setter和Getter的方法名全设置为成员变量的名字。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Accessors(fluent = true)
@Getter
@Setter
public class User {
public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

public User() {};

private Integer id;

private String username;

private String password;
}

编译后的由字节码反编译的代码:

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
public class User {
private Integer id;
private String username;
private String password;

public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

public User() {
}

public Integer id() {
return this.id;
}

public String username() {
return this.username;
}

public String password() {
return this.password;
}

public User id(Integer id) {
this.id = id;
return this;
}

public User username(String username) {
this.username = username;
return this;
}

public User password(String password) {
this.password = password;
return this;
}
}

@ToString

为该类实现一个toString方法。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@ToString
public class User {
public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

public User() {};

private Integer id;

private String username;

private String password;
}

编译后的由字节码反编译的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class User {
private Integer id;
private String username;
private String password;

public User(int id, String username, String password) {
this.id = id;
this.password = password;
this.username = username;
}

public User() {
}

public String toString() {
return "User(id=" + this.id + ", username=" + this.username + ", password=" + this.password + ")";
}
}

还可以通过添加不同参数来限制toString的功能。

includeFieldNames

1
2
@ToString(includeFieldNames = false)
public class User {
1
2
3
public String toString() {
return "User(" + this.id + ", " + this.username + ", " + this.password + ")";
}

默认为True,False状态下tostring隐藏成员变量的类型。

exclude

1
2
@ToString(exclude = {"id"})
public class User {
1
2
3
public String toString() {
return "User(username=" + this.username + ", password=" + this.password + ")";
}

在exclude中添加想要省略的成员变量的名称(字符串),toString函数会省略这些成员变量的转化。

of

1
2
@ToString(of = {"id"})
public class User {
1
2
3
public String toString() {
return "User(id=" + this.id + ")";
}

在of中添加想要显示的成员变量的名称(字符串),toString函数只会完成这些成员变量的转化。(与exclude相反)

callSuper

1
2
@ToString(callSuper = true)
public class User {
1
2
3
4
public String toString() {
String var10000 = super.toString();
return "User(super=" + var10000 + ", id=" + this.id + ", username=" + this.username + ", password=" + this.password + ")";
}

默认为false,改为true后会调用父类的toString()方法。

doNotUseGetters

如果成员变量存在getter方法,在tostring时会默认调用getter方法来获取成员变量。将该值设为true后将直接获取成员变量的值。

onlyExplicitlyIncluded

1
2
@ToString(onlyExplicitlyIncluded = true)
public class User {

默认为false,设为true后将只会显示类名

1
2
3
public String toString() {
return "User()";
}

Include

rank

通过添加rank来规定转化后字符串中变量的顺序。(rank值越大优先级越高

1
2
3
4
5
6
7
8
@ToString.Include(rank = 1)
private Integer id;

@ToString.Include(rank = 0)
private String username;

@ToString.Include(rank = 2)
private String password;
1
2
3
public String toString() {
return "User(password=" + this.password + ", id=" + this.id + ", username=" + this.username + ")";
}
name

设置别名,添加后转化后的字符串中变量的类型将会被别名替换掉

1
2
@ToString.Include(name = "学号")
private Integer id;
1
2
3
public String toString() {
return "User(password=" + this.password + ", 学号=" + this.id + ", username=" + this.username + ")";
}

@EqualsAndHashCode

该标签只允许添加在类前。

重写Equals方法,使得类在比较的过程中对成员变量进行一一的确认,以此来比较是否相等。

该标签也包括exclude和of方法,具体功能和@TosString类似。

@AllArgsConstructor

1
2
@AllArgsConstructor
public class User {
1
2
3
4
5
public User(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}

该标签只能添加在类前,默认为类生成全参数构造。

注意:添加该标签后会使得默认的无参构造方法失效。

该标签也可添加access注解来限制构造方法的访问控制。

1
2
@AllArgsConstructor(access = AccessLevel.PUBLIC)
public class User {

该标签也可添加staticName注解来添加public的静态 类构造方法 ,添加后,原来的无参构造方法的可访问性将被修改成private

1
2
@AllArgsConstructor(staticName = "setUser")
public class User {
1
2
3
4
5
6
7
8
9
private User(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}

public static User setUser(Integer id, String username, String password) {
return new User(id, username, password);
}

可以看到,自动生成了一个名为“setUser”的静态全参构造方法。

@NoArgsConstructor

生成默认的无参构造方法。

1
@NoArgsConstructor(access = AccessLevel.PUBLIC)

其余参数和@AllArgsConstructor一致。

1
2
public User() {
}

@RequiredArgsConstructor

为类中生成包含对标记为final或者@NonNull的成员变量的赋值的构造方法。

1
2
3
4
5
6
@RequiredArgsConstructor
public class User {
@NonNull
private Integer id;

final private String username;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class User {
@NonNull
private Integer id;
private final String username;
private String password;

public User(@NonNull Integer id, String username) {
if (id == null) {
throw new NullPointerException("id is marked non-null but is null");
} else {
this.id = id;
this.username = username;
}
}
}

其余参数和@AllArgsConstructor一致。

@Data

该标签只能添加在类前。

等价于在类前同时添加了@Setter@Getter@RequiredArgsConstructor@ToString@EqualsAndHashCode

添加@Data标签后不推荐对该类进行继承,可能会导致Equals方法异常。

@Value

具体功能和@Data类似。

但是!生成的所有成员变量的属性都是private final的(这意味着没有setter方法)。

@SneakyThrows

该标签只能添加在方法前,表示为该方法添加了try / catch。

1
2
@SneakyThrows(IOException.class)
public void abaaba() {

可以在注解之后添加异常的类来规定抛出的具体异常。

@Cleanup

为该变量自动添加close()方法。

@Builder

1
2
@Builder
public class User {
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
public class User {
private Integer id;
private String username;
private String password;

User(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}

public static User.UserBuilder builder() {
return new User.UserBuilder();
}

public static class UserBuilder {
private Integer id;
private String username;
private String password;

UserBuilder() {
}

public User.UserBuilder id(Integer id) {
this.id = id;
return this;
}

public User.UserBuilder username(String username) {
this.username = username;
return this;
}

public User.UserBuilder password(String password) {
this.password = password;
return this;
}

public User build() {
return new User(this.id, this.username, this.password);
}

public String toString() {
return "User.UserBuilder(id=" + this.id + ", username=" + this.username + ", password=" + this.password + ")";
}
}
}