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 可以给类快速添加 getset 方法,toString() 方法等等。 @Data 注解其实是 @ToString@Getter@SetterRequiredArgsConstructor@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

reference