Content Table

使用 Lombok 自动生成 Getter and Setter

根据 Java Bean 的规范,Bean 就是一个简单的类,主要是属性和访问函数 Getter and Setter 等,都是模版性的代码,虽然有 IDE 帮助我们自动生成,但是代码打开后全是一大堆的访问函数,看上去也不舒服,更郁闷的是,有时候 Bean 有几十个属性,添加一个新的属性后也很容易忘了添加相应的访问函数,而 Java 的很多框架对属性的访问都是使用反射和访问函数来查找的,由于缺少访问函数导致有时候后端得到了数据,但是前端始终缺几个数据,逻辑看上去又没问题,很难得一下发现问题在哪里 (已经发生过好几次)。现在好了,我们可以使用 Lombok 来自动的为 Bean 生成访问函数。

一般使用下面 3 个注解就足够了,没必要搞得更麻烦:

  • @Getter
  • @Setter
  • @Accessors(chain=true)

虽然 @Data 的功能很强大,但是阅读上不够直观,所以不推荐使用。

@Data is equivalent to @Getter, @Setter, @RequiredArgsConstructor, @ToString and @EqualsAndHashCode.

Lombok 不会影响程序的运行性能,它使用 javac 的插件机制在编译阶段生成访问函数到 class 的字节码里,和我们直接写没有什么区别,反编译一下生成的 class 文件就一目了然了。

Gradle 依赖

1
compile 'org.projectlombok:lombok:1.16.14'

使用 Lombok 的 Bean

  • 只需要在类名前加上 @Getter, @Setter 即可 (Lombok 还有其他几个注解,不过没必要使用,影响代码的可读性)。
  • 如果我们提供了属性的访问函数,则 Lombok 不会为其再生成。
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
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Accessors(chain=true) // 可以链式调用 setter
public class User {
private int id;
private String username;
private String email;

public User() {
}

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

// 如果提供了访问函数,则 Lombok 不会为其再生成
public String getEmail() {
return "Email: " + email;
}
}

测试

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {
User user = new User(1, "Alice", "alice@gmail.com");
System.out.println(user.getUsername());
System.out.println(user.getEmail());
// 可以链式调用 setter,当有很多个属性需要设置时非常方便
user.setUsername("Bob").setEmail("bob@gmail.com");
}
}

输出:

Alice
Email: alice@gmail.com

Lombok 插件

为了让 IDEA 对 Lombok 进行支持,需要安装 Lombok 插件 (Eclipse 也有相应的插件),否则在 IDEA 里编辑时提示找不到 Getter and Setter,不过编译运行仍然没问题,因为编译阶段会生成它们

不用 Lombok 的 Bean

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

public User() {
}

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

public int getId() {
return id;
}

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

public String getUsername() {
return username;
}

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

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}

如果有 20,30,40 个属性,想象这个类的 Getter and Setter 会有多少,这个类最后会有多少代码。

@Builder

Lombok 还可以使用 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
import com.alibaba.fastjson.JSON;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {
private int id;
private String username;
private String email;

public User() {
}

@Builder
public User(int id, String username, String email) {
this.id = id;
this.username = username;
this.email = email;
}

public static void main(String[] args) {
User user = User.builder().id(6).username("Alice").email("alice@gmail.com").build();
System.out.println(JSON.toJSONString(user)); // {"email":"alice@gmail.com","id":6,"username":"Alice"}
}
}

如果 @Builder 作用在类名上,会自动的创建一个包含所有属性为参数的构造函数,这时如果想创建一个无参的构造函数,就必须同时定义一个包含所有属性为参数的构造函数,而且参数的顺序必须和属性定义的顺序一致,否则会出问题,可以手动创建,也可以同时使用这 3 个注解: @Builder @NoArgsConstructor @AllArgsConstructor,还是有点复杂的,为了简单起见,可以在构造函数上使用 @Builder,而不是在类名上,就没有这么多限制了。

推荐: 如果 @Builder 只作用于构造函数上,那就相对容易了,参数的个数和顺序都是随意的。

参考资料