lombok是一个Java库,官方网址是 https://projectlombok.org。它通过对Java字节码进行修改,简化Java开发。这边介绍可以看作是对官方文档的简单介绍,不少例子都是官方文档上,另外官方文档上还有使用lombok和不使用lombok代码的对比,可以加深理解。如果需要更加详细的介绍或者配置,建议大家去官方网站看下。

val

可以使用val作为本地变量声明的类型,替代变量的实际类型。当你使用val的时候,变量的类型会通过初始化表达式推断出。本地变量也可以是final的。

限制条件:

  1. val只作用于本地变量和foreach循环,不能作用于类字段
  2. 必须有初始化表达式,以便于lombok进行推断

举例:

import lombok.val;

public void example{
    // 作用于本地变量
    val a = "123";
    val b = 123;
    System.out.println(a + b);
    
    // 作用于foreach循环
    val list = new int[]{1, 2, 3, 4, 5, 6};
    for (val i : list){
        System.out.println(i);
    }
}

@NonNull

作用于方法构造器参数上,自动生成null-check语句。
null-check语句看起来像:

if (param == null) throw new NullPointerException("param")

这条语句会插入方法的的顶部。对构造器来说,会被插入任何显示的this()或者super()调用之后。

如果null-check语句已经在方法或者构造器内部有了,那么不会生成多余的null-check语句。

举例:

public class NonNull {

    private String name;

    public NonNull(@lombok.NonNull String name){
        this.name = name;
    }

    public static void main(String[] args) {
        NonNull notNull = new NonNull(null);// java.lang.NullPointerException: name
    }
}

@Cleanup

可以使用Cleanup来确保资源在退出当前作用域的时候自动清理。你只需要在本地变量加上@Cleanup注解就行。

@Cleanup InputStream in = new FileInputStream("some/file");

这样,当你退出当前作用域的时候,in.close()方法就会被调用。这个方法的调用是用 try/finally 来确保执行的。

如果资源对象没有close()方法,但是有其他的无参方法来释放资源,那么可以在@Cleanup注解中指定方法名:

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

这样,就会调用bar.dispose()方法了。只得注意的是,默认的cleanup方法是close()。如果cleanup方法有参数,那么不能使用@Cleanup。

@Getter / @Setter

这个应该是最常用的功能了。为类属性生成getter/setter方法。

默认的getter/setter方法是public的,除非你显示的指定AccessLevel,这个是@Getter/@Setter的参数。AccessLevel有public,protected,package,private四种。

在类上也可以使用@Getter/@Setter注解,这样该类内的所有非静态属性生成getter/setter方法。

你也可以手动的关闭getter/setter方法的生成,通过指定AccessLevel.NONE,这个会覆盖类上的@Getter、@Setter和@Data注解。

举例:

public class GetterSetter {

    @Getter
    @Setter
    private int age = 10;

    public static void main(String[] args) {
        GetterSetter getterSetter = new GetterSetter();
        getterSetter.setAge(20);
        System.out.println(getterSetter.getAge());
    }

}

@ToString

这个注解作用在类上,生成toString()方法。默认,它会返回类名和每个属性。
可以通过指定includeFieldNames参数来设置是否返回属性的名字,该参数默认是true。
所有的非static属性默认都会返回。如果你还想跳过某些属性,可以指定exclude参数来讲不想输出的参数放在里面。另外一个选择是使用of参数,将想输出的参数放在里面。

将callSuper参数设置成true,就可以包含父类的toString返回值了。

举例:

@lombok.ToString(includeFieldNames = true,callSuper = false,exclude = {"address"})
public class ToString {

    private String name;
    private int age;
    private String address;

    public ToString(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }


    public static void main(String[] args) {
        ToString toString = new ToString("chengjf", 20, "China");
        System.out.println(toString.toString());
    }
}

@EqualsAndHashCode

该注解作用在类上,用来生成equals(Object other)和hashCode()方法的实现。默认的,会使用所有的非静态,非瞬时的类属性。同样的,你可以使用exclude参数排除你不想使用的类属性,或者使用of参数指定向使用的属性。

当你的类继承自其他的类时,需要特别注意。

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.name;
  }
  
  @EqualsAndHashCode(callSuper=true)
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

这三个注解都是作用在类上的,用来生成合适的构造函数。

@NoArgsContructor生成无参数的构造函数。如果类中有final类属性,构造函数必须要初始化该属性,那么会抛出一个编译错误。但是如果你使用@NoArgsConstructor(force = true),那么所有的final类属性会被初始化成0/false/null。

@RequiredArgsConstructor生成包含所有非final类变量的构造函数。参数的顺序和它们在类中出现的顺序一样。

@AllArgsConstructor生成所有类变量的构造函数。

使用staticName参数,指定一个方法名字,可以为该类生成一个静态方法工厂。然后可以通过该静态方法构造对象,形如SomeClass.of(someargs)。

@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
  private int x, y;
  @NonNull private T description;
  
  @NoArgsConstructor
  public static class NoArgsExample {
    @NonNull private String field;
  }
}

@Data

该注解是一个快捷方式,包含了@ToString,@EqualsAndHashCode,@Getter/Setter和@RequiredArgsConstructor注解。

如果某个注解有自己的特殊处理,那么需要进行单独的设置。

举例:

import lombok.AccessLevel;
import lombok.Setter;
import lombok.Data;
import lombok.ToString;

@Data
public class DataExample {
    private final String name;
    @Setter(AccessLevel.PACKAGE)
    private int age;
    private double score;
    private String[] tags;

    @ToString(includeFieldNames = true)
    @Data(staticConstructor = "of")
    public static class Exercise<T> {
        private final String name;
        private final T value;
    }
}

@Value

@Value注解是@Data注解的不可变的版本。所有的类属性默认都是private和final的,setter方法不会生成。类本身也被标记成了final。toString()、equals()和hashCode()方法也会生成。每个类属性都有getter方法。然后,还有一个包含所有类属性字段的构造方法(除了已经初始化的final类属性)。

实际上,@Value=final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefault(makeFinal = true, level = AcessLevel.PRIVATE) @Getter。

举例:

@Value
    public class ValueExample {
        String name;
        @Wither(AccessLevel.PACKAGE)
        @NonFinal
        int age;
        double score;
        protected String[] tags;

        @ToString(includeFieldNames = true)
        @Value(staticConstructor = "of")
        public static class Exercise<T> {
            String name;
            T value;
        }
    }

@Builder

该注解为类生成builder API。

形如:

Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();

举例:

@Builder
public class BuilderExample {
  private String name;
  private int age;
  @Singular private Set<String> occupations;
}

@SneakyThrows

该注解会为你偷偷的抛出检查异常(checkd exceptions),代替你手动在你的方法里写throws语句。

该英爱只用在下面这两种情况下:

  • 一些非必要的接口中,比如Runnable接口
  • 一些不可能的异常,比如 new String(someByteArray, "UTF-8")

举例:

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

@Synchronized

类似于synchronized关键字,作用于方法上。同synchronized不同的是,它锁的对象不是this,而是一个类属性lock对象。

如果该变量不存在,会生成一个。如果该注解作用在static方法上,锁对象会替换成静态的LOCK对象。

如果自己定义了锁对象,那么可以在@Synchronized的参数里指定。

举例:

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");
    }
}

@Getter(lazy=true)

生成一个getter方法,只求一次值。第一个getter访问的时候,计算出该值,然后将该值缓存起来,后面在调用该方法的时候,直接从缓存中取值返回即可。这个对于占用大量CPU或者占用很多内存的方法来说非常有用。

使用该特性,需要创建一个private final的变量,通过表达式进行初始化,然后给该变量加上@Getter(lazy = true)注解。

举例:

public class GetterLazyExample {
    @Getter(lazy = true)
    private final double[] cached = expensive();

    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

@Log

这个也是我常用的注解。该注解有下面这几种:

  • @CommonsLog
    private static final org.apche.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(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);

举例

@Log
public class LogExample {
  
  public static void main(String... args) {
    log.error("Something's wrong here");
  }
}

标签: Java, lombok

添加新评论