coding……
但行好事 莫问前程

Java开发利器Lombok

  • Lombok简介

Lombok是一种Java的实用工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现Lombok,开发人员可以节省构建getter/setter以及诸如hashCode()和equals()这样的方法。Lombok会在编译时修改插入代码,因此不会影响任何运行时的性能。

  • 安装Lombok

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
    <scope>provided</scope>
</dependency>

Jetbrains IntelliJ IDEA用户需要安装插件

  • Lombok用法

  • @Data注解

@Data直接修饰POJO或者beans, getter所有的变量,setter所有不为final的变量。如果不需要默认的生成方式,直接填写你需要的annotation的就可以了。默认生成的所有的annotation都是public的,如果需要不同权限修饰符可以使用AccessLevel选项。当然@Data 也可以使用staticConstructor选项生成一个静态方法。包含了以下几种注解:

注解 生成 选项
@Getter / @Setter getter / setter 方法 /
@ToString toString方法 includeFieldNames,toString方法是否输出成员变量名,可选值true/false,默认为true
@EqualsAndHashCode equals()和hashCode()方法 /
@RequiredArgsConstructor   包含非空参数(未初始化的final成员变量或者@NonNull成员变量)的构造器 /

POJO添加了@Data注解,相当于添加了上述五个注解,示例代码:

@Data
public class DataExample {
    private final String name;

    private final String name1 = "zhuoli";

    @NonNull
    private String name2;

    @NonNull
    private String name3 = "zhuoli";

    @Setter(AccessLevel.PACKAGE)
    private int age;

    private double score;

    private String[] tags;

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

编译后生成的class文件:

public class DataExample {
    private final String name;
    private final String name1 = "zhuoli";
    @NonNull
    private String name2;
    @NonNull
    private String name3 = "zhuoli";
    private int age;
    private double score;
    private String[] tags;

    public DataExample(String name, @NonNull String name2) {
        if (name2 == null) {
            throw new NullPointerException("name2");
        } else {
            this.name = name;
            this.name2 = name2;
        }
    }

    public String getName() {
        return this.name;
    }

    public String getName1() {
        this.getClass();
        return "zhuoli";
    }

    @NonNull
    public String getName2() {
        return this.name2;
    }

    @NonNull
    public String getName3() {
        return this.name3;
    }

    public int getAge() {
        return this.age;
    }

    public double getScore() {
        return this.score;
    }

    public String[] getTags() {
        return this.tags;
    }

    public void setName2(@NonNull String name2) {
        if (name2 == null) {
            throw new NullPointerException("name2");
        } else {
            this.name2 = name2;
        }
    }

    public void setName3(@NonNull String name3) {
        if (name3 == null) {
            throw new NullPointerException("name3");
        } else {
            this.name3 = name3;
        }
    }

    public void setScore(double score) {
        this.score = score;
    }

    public void setTags(String[] tags) {
        this.tags = tags;
    }

    public boolean equals(Object o) {
        //省略
    }

    protected boolean canEqual(Object other) {
        return other instanceof DataExample;
    }

    public int hashCode() {
    }

    public String toString() {
        return "DataExample(name=" + this.getName() + ", name1=" + this.getName1() + ", name2=" + this.getName2() + ", name3=" + this.getName3() + ", age=" + this.getAge() + ", score=" + this.getScore() + ", tags=" + Arrays.deepToString(this.getTags()) + ")";
    }

    void setAge(int age) {
        this.age = age;
    }

    public static class Exercise<T> {
        private final String name;
        private final T value;

        public String toString() {
            return "DataExample.Exercise(" + this.getName() + ", " + this.getValue() + ")";
        }

        private Exercise(String name, T value) {
            this.name = name;
            this.value = value;
        }

        public static <T> DataExample.Exercise<T> of(String name, T value) {
            return new DataExample.Exercise(name, value);
        }

        public String getName() {
            return this.name;
        }

        public T getValue() {
            return this.value;
        }

        public boolean equals(Object o) {
            //省略
        }

        protected boolean canEqual(Object other) {
            return other instanceof DataExample.Exercise;
        }

        public int hashCode() {
            //省略
        }
    }
}

值得注意的是name1和name3因为已经初始化,生成的构造函数参数中不包含这两项,@Setter使用了AccessLevel.PACKAGE选项,所以生成的setter方法美加权限修饰符,为包访问权限。Exercise内部@ToString注解添加了includeFieldNames=false选项,所以生成的toString方法不包含变量名,@Data添加了staticConstructor=”of”属性,所以生成了静态构造函数of。

  • @Value注解

@Value与@Data的主要区别就是,如果成员变量不加@NonFinal ,编译后生成的类所有的成员变量都会是final的,相应的,就没有set方法了,示例代码:

@Value
public class ValueExample {
    private String name;

    @Wither(AccessLevel.PACKAGE)
    @NonFinal
    private int age;

    private double score;
    protected String[] tags;

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

编译后生成的class文件:

public final class ValueExample {
    private final String name;
    private int age;
    private final double score;
    protected final String[] tags;

    public ValueExample(String name, int age, double score, String[] tags) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.tags = tags;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    public double getScore() {
        return this.score;
    }

    public String[] getTags() {
        return this.tags;
    }

    public boolean equals(Object o) {
        //省略
    }

    public int hashCode() {
        //省略
    }

    public String toString() {
        return "ValueExample(name=" + this.getName() + ", age=" + this.getAge() + ", score=" + this.getScore() + ", tags=" + Arrays.deepToString(this.getTags()) + ")";
    }

    ValueExample withAge(int age) {
        return this.age == age ? this : new ValueExample(this.name, age, this.score, this.tags);
    }

    public static final class Exercise<T> {
        private final String name;
        private final T value;

        private Exercise(String name, T value) {
            this.name = name;
            this.value = value;
        }

        public static <T> ValueExample.Exercise<T> of(String name, T value) {
            return new ValueExample.Exercise(name, value);
        }

        public String getName() {
            return this.name;
        }

        public T getValue() {
            return this.value;
        }

        public boolean equals(Object o) {
            //省略
        }

        public int hashCode() {
            //省略
        }

        public String toString() {
            return "ValueExample.Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
        }
    }
}

可以看到,除了@NonFinal标注的成员变量age,其他成员变量编译后都变成final,但是age成员变量出现在了构造函数中(这一点跟@RequiredArgsConstructor注解有点违背,我也每太看懂)。同时生成了一个包访问权限的WithAge方法,返回一个类实例,不多说,看一下代码就能看懂

  • @Builder注解

@Builder注解标注在类、构造器或方法上,可生成各种builder APIs,允许开发者以如下方式调用:

Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
@Builder
@ToString
@Getter
public class BuilderExample {
    /*如果created没有被build赋值,则取默认值*/
    @Builder.Default
    private long created = System.currentTimeMillis();

    private String name;

    private int age;

    /*表明成员变量是collection*/
    @Singular
    private Set<String> occupations;
}

调用示例:

@Test
public void builderTest(){
    BuilderExample builderExample = BuilderExample.builder().name("zhuoli").age(22).occupation("haha").build();
    assertThat(builderExample.getOccupations(), containsInAnyOrder("haha"));

    BuilderExample builderExample1 = BuilderExample.builder().occupations(Sets.newHashSet("this", "is", "builder")).build();
    assertThat(builderExample1.getOccupations(), containsInAnyOrder("this", "is", "builder"));
}
  • @Log注解

@Log注解标注在类上,并根据不同的注解生成不同类型的日志logger对象,但是实例名称都是log,修饰属性都是private static final,目前支持以下几种logger:

注解 生成对象
@CommonsLog org.apache.commons.logging.Log
@JBossLog org.jboss.logging.Logger
@Log java.util.logging.Logger
@Log4j org.apache.log4j.Logger
@Log4j2 org.apache.log4j.LogManager
@Slf4j org.slf4j.Logger
@XSlf4j org.slf4j.ext.XLogger

如@CommonsLog相当于:

private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Slf4j相当于:

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

更多细节,请参考官方文档

  • @XXXConstructor注解

该系列注解提供自动生成构造函数的功能,主要分为以下三类:

注解 生成构造器
@NoArgsConstructor 无参构造器
@RequiredArgsConstructor 包含非空参数(未初始化的final成员变量或者@NonNull成员变量)的构造器
@AllArgsConstructor 包含所有非static成员、未初始化的final成员的构造器
@AllArgsConstructor
public class AllArgsConstructorExample {
    private Integer x;

    private Integer y;

    private static Integer z;

    private final Integer z1;

    private final Integer z2 = 2;

    private static final Integer z3 = 1;
}

编译后生成的代码:

public class AllArgsConstructorExample {
    private Integer x;
    private Integer y;
    private static Integer z;
    private final Integer z1;
    private final Integer z2 = 2;
    private static final Integer z3 = 1;

    public AllArgsConstructorExample(Integer x, Integer y, Integer z1) {
        this.x = x;
        this.y = y;
        this.z1 = z1;
    }
}

static成员变量z、z3,已初始化的成员变量z2没有出现在构造函数中

  • @NonNull注解

@NonNull注解提供成员变量的非空检查

public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
}
// 等同于
public NonNullExample(Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
}
  • @SneakyThrows注解

@SneakyThrows注解的方法会自动抛出受检异常,而无需显式在方法上使用throws语句

  • @Synchronized注解

@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");
    }
  }
}
  • @Getter(lazy=true)注解

@Getter(lazy=true)注解可以替代经典的Double Check Lock样板代码,实现单例,示例代码:

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;
  }
}
// 等同于
 public class GetterLazyExample {
  private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<>();
  public double[] getCached() {
    java.lang.Object value = this.cached.get();
    if (value == null) {
      synchronized(this.cached) {
        value = this.cached.get();
        if (value == null) {
          final double[] actualValue = expensive();
          value = actualValue == null ? this.cached : actualValue;
          this.cached.set(value);
        }
      }
    }
    return (double[])(value == this.cached ? null : value);
  }
  private double[] expensive() {
    double[] result = new double[1000000];
    for (int i = 0; i < result.length; i++) {
      result[i] = Math.asin(i);
    }
    return result;
  }
}

示例代码:码云 – 卓立 – lombok

参考链接:

  1. Lombok官方文档
  2. Lombok——減少Java樣板代碼的利器

赞(0) 打赏
Zhuoli's Blog » Java开发利器Lombok
分享到: 更多 (0)

相关推荐

  • 暂无文章

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址