lombok 在编译器编译时通过操作 AST(抽象语法树)改变字节码生成。也就是说他可以改变 Java 语法。lombok 不像 Spring 的依赖注入是运行时的特性,而是编译时的特性。使用 lombok 需要对应 IDE 插件配合,具体可参考官网。
安装配置
官网地址:https://projectlombok.org/
添加 maven
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
最新的版本号,可以在官网或者 mvnrepository 找到。 如果使用 Intellij IDEA 还需要安装一个插件。
使用
Data 注解
类注解
import lombok.Data;
@Data
public class Thing {
private Long id;
private String desc;
}
通过添加注解 @Data
可以给类快速添加 get
和 set
方法,toString()
方法等等。 @Data
注解其实是 @ToString
,@Getter
,@Setter
,RequiredArgsConstructor
,@EqualsAndHashCode
注解的缩写。
其实等效于
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@ToString
@RequiredArgsConstructor
@EqualsAndHashCode
public class Thing {
@Setter @Getter private Long id;
@Setter @Getter private String desc;
}
相关的注解:
@Getter/@Setter
:用在属性上,再也不用自己手写 setter 和 getter 方法了,还可以指定访问范围@ToString
:用在类上,可以自动覆写 toString 方法,当然还可以加其他参数,例如 @ToString(exclude=”id”) 排除 id 属性,或者 @ToString(callSuper=true, includeFieldNames=true) 调用父类的 toString 方法,包含所有属性@EqualsAndHashCode
:用在类上,自动生成 equals 方法和 hashCode 方法@NoArgsConstructor
,@RequiredArgsConstructor
and@AllArgsConstructor
:用在类上,自动生成无参构造和使用所有参数的构造函数以及把所有 @NonNull 属性作为参数的构造函数,如果指定 staticName = “of”参数,同时还会生成一个返回类对象的静态工厂方法,比使用构造函数方便很多@Data
:注解在类上,相当于同时使用了@ToString
、@EqualsAndHashCode
、@Getter
、@Setter
和@RequiredArgsConstrutor
这些注解,对于 POJO 类十分有用@Value
:用在类上,是 @Data 的不可变形式,相当于为属性添加 final 声明,只提供 getter 方法,而不提供 setter 方法@NonNull
用在方法参数上,该变量不能为空,否则就抛出异常@Builder
:用在类、构造器、方法上,为你提供复杂的 builder APIs,让你可以像如下方式一样调用 Person.builder().name(“Adam Savage”).city(“San Francisco”).job(“Mythbusters”).job(“Unchained Reaction”).build(); 更多说明参考 Builder@SneakyThrows
:自动抛受检异常,而无需显式在方法上使用 throws 语句@Synchronized
:用在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性 $lock 或 $LOCK,而 java 中的 synchronized 关键字锁对象是 this,锁在 this 或者自己的类对象上存在副作用,就是你不能阻止非受控代码去锁 this 或者类对象,这可能会导致竞争条件或者其它线程错误@Getter
(lazy=true):可以替代经典的 Double Check Lock 样板代码-
@Log
:根据不同的注解生成不同类型的 log 对象,但是实例名称都是 log,有六种可选实现类@CommonsLog Creates log = org.apache.commons.logging.LogFactory.getLog(LogExample.class); @Log Creates log = java.util.logging.Logger.getLogger(LogExample.class.getName()); @Log4j Creates log = org.apache.log4j.Logger.getLogger(LogExample.class); @Log4j2 Creates log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class); @Slf4j Creates log = org.slf4j.LoggerFactory.getLogger(LogExample.class); @XSlf4j Creates log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
ToString 注解
Slf4j 注解
正如上面所例举,lombok 可以使用的日志框架有很多,拿最常见的 @Slf4j
来举例
@Slf4j
public class A {
public A() {
log.info("I'm sectionVO : {}", toString());
}
}
编译会自动生成
private static final Logger log = LoggerFactory.getLogger(A.class);
Builder 注解
如果在类上使用 @Builder
注解,则会给该类直接生成 builder 模式,然后可以使用 builder() 方法返回的 builder 来构造类。
如果要对 Builder 中的值赋予默认值,有两种方式,比如对于
@Builder
public class Person {
private String firstname = "John";
private String lastname = "Doe";
}
第一种方式就是手动编写一个静态内部类
@Builder
public class Person {
private String firstname;
private String lastname;
private String middleName;
public static class PersonBuilder {
private String firstname = "John";
private String lastname = "Doe";
}
}
或者在 v1.16.16 之后添加的新功能
@Builder
public class Person {
@Builder.Default private String firstname = "John";
@Builder.Default private String lastname = "Doe";
private String middleName;
}
当一个类被标注 @Builder
后会自动产生下面 7 件事情:
- 一个内部静态类
FooBuilder
,类内部有着和类相同类型的内部变量 - builder 内部:One private non-static non-final field for each parameter of the target
- builder 内部:package private no-args empty constructor
- builder 内部:A ‘setter’-like method for each parameter of the target: It has the same type as that parameter and the same name. It returns the builder itself, so that the setter calls can be chained, as in the above example.
- builder 内部:A build() method which calls the method, passing in each field. It returns the same type that the target returns.
- builder 内部:A sensible toString() implementation.
- builder 内部:A builder() method, which creates a new instance of the builder.
最后,如果在类上注解 @AllArgsConstructor(access = AccessLevel.PACKAGE)
那么可以将 @Builder
应用到类上。如果自己显示定义了构造函数,那么将 @Builder
用在该构造方法上。
总结 Lombok 实践
- Lombok 注解的内容不要参杂任何逻辑
- 在 DAOs 上使用 @Data
- 对不可变对象使用 @Value
- 当类有很多相同类型成员变量,使用 @Builder
- 慎用其他不常用注解,比如 @Cleanup,@SneakyThrows,@Synchronized 等
其他的特性可以在这里看到:https://projectlombok.org/features/all