Lombok 教程
Lombok 常规操作,以及一些好的用法。

前言

官方文档

@RequiredArgsConstructor

可以用在类上,使用类中所有带有 @NonNull 注解的或者带有 final 修饰的成员变量生成对应的构造方法

编写优雅的 Spring 依赖注入代码:

@RequiredArgsConstructor(onConstructor=@__(@Autowired))
public class PunchclockService {

  private final OkHttpClient okHttpClient;
  
  ...
  
}

@AllArgsConstructor

可以用在类上,为类提供一个全参的构造方法

@NoArgsConstructor

可以用在类上,为类提供一个无参的构造方法

@NonNull

可以在方法或构造函数的参数上使用 @NonNulllombok 为生成 null-check 语句。

编译前:

import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;
  
  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

编译后:

import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;
  
  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person is marked @NonNull but is null");
    }
    this.name = person.getName();
  }
}

@Cleanup

可以使用 @Cleanup 确保在代码执行路径退出当前作用域之前自动清除给定资源

编译前:

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}

编译后:

import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        if (out != null) {
          out.close();
        }
      }
    } finally {
      if (in != null) {
        in.close();
      }
    }
  }
}

如果要清理的对象类型没有 close() 方法,而是其他一些无参数方法,则可以指定此方法的名称,如下所示:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

不能通过@Cleanup调用带有1个或多个参数的清理方法。

@Getter and @Setter

可以使用 @Getter/@Setter 注释任何字段,让 lombok 自动生成默认的 getter / setter, 也可以注释整个类

编译前:

public class Person {

  @Getter @Setter private int age = 1;

  @Setter(AccessLevel.PROTECTED) private String name;
  
}

编译后:

public class Person {

  private int age = 10;

  private String name;
  
  public int getAge() {
    return age;
  }
  
  public void setAge(int age) {
    this.age = age;
  }
  
  protected void setName(String name) {
    this.name = name;
  }
  
}

@ToString

任何类定义都可以用 @ToString 注释,让 lombok 生成 toString() 方法的实现

编译前:

@ToString
public class ToStringExample {
  private String name;
}

编译后:

@ToString
public class ToStringExample {
  private String name;
  @Override public String toString() {
    return "ToStringExample(" + this.getName() + ")";
  }
}

@EqualsAndHashCode

任何类定义都可以用 @EqualsAndHashCode 注释,生成 equalscanEqualhashCode

@Data

可以使用 @Data 作用在类上,生成 @ToString + @EqualsAndHashCode + @Getter / @Setter

@Value

可以使用 @Value 作用在类上,会生成含所有参数的构造方法 + @Getter + @ToString + @EqualsAndHashCode 方法

@Builder

可以使用 @Builder 作用在类上,生成复杂的构建器API

编译前:

@Builder
public class BuilderExample {
  @Builder.Default private long created = System.currentTimeMillis();
  private String name;
  private int age;
  @Singular private Set<String> occupations;
}

编译后:

public class BuilderExample {
  private long created;
  private String name;
  private int age;
  private Set<String> occupations;
  
  BuilderExample(String name, int age, Set<String> occupations) {
    this.name = name;
    this.age = age;
    this.occupations = occupations;
  }
  
  private static long $default$created() {
    return System.currentTimeMillis();
  }
  
  public static BuilderExampleBuilder builder() {
    return new BuilderExampleBuilder();
  }
  
  public static class BuilderExampleBuilder {
    private long created;
    private boolean created$set;
    private String name;
    private int age;
    private java.util.ArrayList<String> occupations;
    
    BuilderExampleBuilder() {
    }
    
    public BuilderExampleBuilder created(long created) {
      this.created = created;
      this.created$set = true;
      return this;
    }
    
    public BuilderExampleBuilder name(String name) {
      this.name = name;
      return this;
    }
    
    public BuilderExampleBuilder age(int age) {
      this.age = age;
      return this;
    }
    
    public BuilderExampleBuilder occupation(String occupation) {
      if (this.occupations == null) {
        this.occupations = new java.util.ArrayList<String>();
      }
      
      this.occupations.add(occupation);
      return this;
    }
    
    public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
      if (this.occupations == null) {
        this.occupations = new java.util.ArrayList<String>();
      }

      this.occupations.addAll(occupations);
      return this;
    }
    
    public BuilderExampleBuilder clearOccupations() {
      if (this.occupations != null) {
        this.occupations.clear();
      }
      
      return this;
    }

    public BuilderExample build() {
      // complicated switch statement to produce a compact properly sized immutable set omitted.
      Set<String> occupations = ...;
      return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations);
    }
    
    @java.lang.Override
    public String toString() {
      return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
    }
  }
}

@SneakyThrows

在实际开发中 @SneakyThrows 不够灵活,但是在一些确定不太可能发生异常的地方但是又必须 cache checked exception 的地方,可以提高代码的可读性。

编译前:

public class SneakyThrowsExample implements Runnable {
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) {
    return new String(bytes, "UTF-8");
  }
}

编译后:

public class SneakyThrowsExample implements Runnable {
  public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
  }
}

@Synchronized

官方解释: @Synchronizedsynchronized 方法修饰符的更安全的变体。与 synchronized 一样,注释只能用于静态和实例方法。@Synchronized 的操作类似于 synchronized 关键字,但它锁定在不同的对象上。 关键字 synchronized 锁定 this ,但 @Synchronized 锁定在名为 $lock 的字段上,并且该字段是私有的。(如果该字段不存在,则会为你创建该字段。)如果注释静态方法,则注释会锁定名为 $LOCK 的静态字段。

编译前:

public class SynchronizedExample {
  private final Object readLock = new Object();
  
  @Synchronized
  public static void hello() {
    System.out.println("world");
  }
  
  @Synchronized
  public int answerToLife() {
    return 42;
  }
  
  @Synchronized("readLock")
  public void foo() {
    System.out.println("bar");
  }
}

编译后:

public class SynchronizedExample {
  private static final Object $LOCK = new Object[0];
  private final Object $lock = new Object[0];
  private final Object readLock = new Object();
  
  public static void hello() {
    synchronized($LOCK) {
      System.out.println("world");
    }
  }
  
  public int answerToLife() {
    synchronized($lock) {
      return 42;
    }
  }
  
  public void foo() {
    synchronized(readLock) {
      System.out.println("bar");
    }
  }
}

@Log相关

@CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Flogger
private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
@JBossLog
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

最后修改于 2019-06-13

此篇文章的评论功能已经停用。