对于这样一个简单的 Java 类,我们通常需要给每个属性写 `getXXX()` 和 `setXXX()` 方法,有时候还要重写 `equals()`、 `hashCode()`、 `toString()`等方法。在开发的过程中,重复编写这些“没有技术含量”的代码,对程序员来说是一个很枯燥无趣的事情,也增加了很大的工作负担。 针对这种情况,Lombok 提供了一种机制,基于注解的方式,帮助我们自动生成这些样板代码
什么是Lombok
一个典型的Java类
public class A {
private int num;
private String str;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof A)) return false;
A a = (A) o;
if (getNum() != a.getNum()) return false;
return getStr() != null ? getStr().equals(a.getStr()) : a.getStr() == null;
}
@Override
public int hashCode() {
int result = getNum();
result = 31 * result + (getStr() != null ? getStr().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "A{" + "num=" + num + ", str='" + str + '\'' + '}';
}
}
对于这样一个简单的 Java 类,我们通常需要给每个属性写 getXXX()
和 setXXX()
方法,有时候还要重写 equals()
、 hashCode()
、toString()
等方法。在开发的过程中,重复编写这些“没有技术含量”的代码,对程序员来说是一个很枯燥无趣的事情,也增加了很大的工作负担。
针对这种情况,Lombok 提供了一种机制,基于注解的方式,帮助我们自动生成这些样板代码。如:
@Data
public class A {
private int a;
private String b;
}
@Data
就是 Lombok 的一个注解,它所做的工作包括生成了所有属性的 getXXX()
和 setXXX()
方法,重写了equals()
、 hashCode()
、toString()
方法。
将 lombok.jar 拷贝到 A.java 文件所在目录进行编译:
javac -cp lombok.jar A.java && javap -public A.class
public class com.tuniu.calliper.component.view.controller.A {
public com.tuniu.calliper.component.view.controller.A();
public int getNum();
public java.lang.String getStr();
public void setNum(int);
public void setStr(java.lang.String);
public boolean equals(java.lang.Object);
public int hashCode();
public java.lang.String toString();
}
可以看到生成的方法。反观未加入 @Data
注解的 A.java, 编译后为:
public class com.tuniu.calliper.component.view.controller.A {
public com.tuniu.calliper.component.view.controller.A();
}
使用
具体的安装和引入可参考 Lombok官网。需要说明的是,如果 IDE 不安装插件,同样可以通过编译,但是,在IDE中会提示报错,
并在编写代码时,不会出现方法提示,影响使用。
Lombok的运行机制
Lombok主要基于Java中的注解生成代码,以@Setter方法为例(具体源码可查看 Lombok项目源码),其注解定义如下:
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Setter {
lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;
AnyAnnotation[] onMethod() default {};
AnyAnnotation[] onParam() default {};
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
@interface AnyAnnotation {}
}
可以发现,@Setter 是源码级别的,即在编译期有效。我们知道,在 Java 中,Java 编译主要分为三大部分:
- 分析和输入到符号表
- 注解处理(可选)
- 语义分析和生成 class 文件
Lombok 的注解都是在编译期的第二个阶段,也就是注解处理阶段去解析注解,并生成对应的源码,然后重新编译修改后的源文件,最后在class文件中包含对应的方法。
需要注意的是,在 javac 编译器中,注解处理 机制是默认打开的,而对于 eclipse 这种自带编译器( ECJ )的 IDE 是默认不打开的,这也就是为什么 IDE 要安装插件
的原因。
Lombok注解
Lombok 目前最新版本为1.16.8,主要提供16种注解,个人觉得比较常用的有以下几种,更多可查看 Lombok官网。
- @Getter / @Setter
作用于属性和类上,自动生成属性的getXXX()
和setXXX()
方法。若在类上,则对所有属性有效。并可通过AccessLevel参数控制方法的访问级别。 - @ToString
作用于类,自动重写类的ToString()
方法。常用的参数有exclude
(指定方法中不包含的属性)、callSuper
(方法中是否包含父类ToString()
方法返回的值) - @EqualsAndHashCode
作用于类,自动重写类的equals()
、hashCode()
方法。常用的参数有exclude
(指定方法中不包含的属性)、callSuper
(方法中是否包含父类ToString()
方法返回的值) - @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
作用于类,@NoArgsConstructor
自动生成不带参数的构造方法;@RequiredArgsConstructor
自动生成带参数的构造方法,主要针对一些需要特殊处理的属性,比如未初始化的final
属性;@AllArgsConstructor
自动生成包含所有属性的构造方法。 - @Data
@ToString
、@EqualsAndHashCode
、@Getter
、@Setter
和@RequiredArgsConstructor
注解的集合。 - @Synchronized
作用于方法,可锁定指定的对象,如果不指定,则默认创建创建一个对象锁定。 - @Log
作用于类,具体包含@CommonsLog
、@Log
、@Log4j
、@Log4j2
、@Slf4j
和@XSlf4j
,分别对用不同的日志系统。利用此类注解,可为类创建一个log
属性。