博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lombok老母猪
阅读量:4090 次
发布时间:2019-05-25

本文共 17288 字,大约阅读时间需要 57 分钟。

关于Lombok,其实在网上可以找到很多如何使用的文章,但是很少能找到比较齐全的整理。我也一直寻思着想写一篇各个注解用法的总结,但是一直都没有付诸行动。今天看到了微信公众号”原力注入”推送的这篇文章,总结的内容很全,所以分享给所有关注我博客的朋友们。

Lombok简介

Project Lombok makes java a spicier language by adding ‘handlers’ that know >how to build and compile simple, boilerplate-free, not-quite-java code.

如Github上项目介绍所言,Lombok项目通过添加“处理程序”,使java成为一种更为简单的语言。作为一个Old Java Developer,我们都知道我们经常需要定义一系列的套路,比如定义如下的格式对象。

public class DataExample {  private final String name;  private int age;  private double score;  private String[] tags;}

我们往往需要定义一系列的Get和Set方法最终展示形式如:

public class DataExample {  private final String name;  private int age;  private double score;  private String[] tags;  public DataExample(String name) {    this.name = name;  }  public String getName() {    return this.name;  }  void setAge(int age) {    this.age = age;  }  public int getAge() {    return this.age;  }  public void setScore(double score) {    this.score = score;  }  public double getScore() {    return this.score;  }  public String[] getTags() {    return this.tags;  }  public void setTags(String[] tags) {    this.tags = tags;  }}

那我们有没有可以简化的办法呢,第一种就是使用IDEA等IDE提供的一键生成的快捷键,第二种就是我们今天介绍的 Lombok项目:

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

Wow…这样就可以完成我们的需求,简直是太棒了,仅仅需要几个注解,我们就拥有了完整的GetSet方法,还包含了ToString等方法的生成。

Lombok安装

整个Lombok只有一个Jar包,可到这里下载:

Lombok支持多种使用安装方式,这里我们讲最常见的对两大IDE的支持:

Eclipse (含延伸版本)

双击打开 lombok.jar (前提:你得装了JDK), 可见如下页面点击 Install/Update:

恭喜你,已经安装成功了。我们打开 Eclipse 的 About 页面我们可以看见。

IntelliJ IDEA

  • 定位到 File > Settings > Plugins
  • 点击 Browse repositories…
  • 搜索 Lombok Plugin
  • 点击 Install plugin
  • 重启 IDEA

更多安装请参考:

Lombok使用

Lombok 其实也不能算是一个特别新的项目,从 2011 开始在中心仓库提供支持,现在也分为 stable 和 experimental 两个版本,本文侧重介绍 stable 功能:

val

如果对其他的语言有研究的会发现,很多语言是使用 var 作为变量申明,val作为常量申明。这里的val也是这个作用。

public String example() {    val example = new ArrayList
(); example.add("Hello, World!"); val foo = example.get(0); return foo.toLowerCase();}

翻译成 Java 程序是:

public String example() {    final ArrayList
example = new ArrayList
(); example.add("Hello, World!"); final String foo = example.get(0); return foo.toLowerCase();}

作者注:也就是类型推导啦。

@NonNull

Null 即是罪恶

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

翻译成 Java 程序是:

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

@Cleanup

自动化才是生产力

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

翻译成 Java 程序是:

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

作者注: JKD7里面就已经提供 try with resource

@Getter/@Setter

再也不写 public int getFoo() {return foo;}

public class GetterSetterExample {  @Getter @Setter private int age = 10;    @Setter(AccessLevel.PROTECTED) private String name;    @Override public String toString() {    return String.format("%s (age: %d)", name, age);  }}

翻译成 Java 程序是:

public class GetterSetterExample {  private int age = 10;  private String name;    @Override public String toString() {    return String.format("%s (age: %d)", name, age);  }    public int getAge() {    return age;  }    public void setAge(int age) {    this.age = age;  }    protected void setName(String name) {    this.name = name;  }}

@ToString

Debug Log 最强帮手

@ToString(exclude="id")public class ToStringExample {  private static final int STATIC_VAR = 10;  private String name;  private Shape shape = new Square(5, 10);  private String[] tags;  private int id;    public String getName() {    return this.getName();  }    @ToString(callSuper=true, includeFieldNames=true)  public static class Square extends Shape {    private final int width, height;        public Square(int width, int height) {      this.width = width;      this.height = height;    }  }}

翻译后:

public class ToStringExample {  private static final int STATIC_VAR = 10;  private String name;  private Shape shape = new Square(5, 10);  private String[] tags;  private int id;    public String getName() {    return this.getName();  }    public static class Square extends Shape {    private final int width, height;        public Square(int width, int height) {      this.width = width;      this.height = height;    }        @Override public String toString() {      return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";    }  }    @Override public String toString() {    return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";  }}

作者注:其实和 org.apache.commons.lang3.builder.ReflectionToStringBuilder 很像。

@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

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

翻译后:

public class ConstructorExample
{ private int x, y; @NonNull private T description; private ConstructorExample(T description) { if (description == null) throw new NullPointerException("description"); this.description = description; } public static
ConstructorExample
of(T description) { return new ConstructorExample
(description); } @java.beans.ConstructorProperties({"x", "y", "description"}) protected ConstructorExample(int x, int y, T description) { if (description == null) throw new NullPointerException("description"); this.x = x; this.y = y; this.description = description; } public static class NoArgsExample { @NonNull private String field; public NoArgsExample() { } }}

@Data

这个就相当的简单啦,因为我们发现@ToString@EqualsAndHashCode@Getter都很常用,这个一个注解就相当于

@ToString@EqualsAndHashCode@Getter(所有字段)@Setter (所有非final字段)@RequiredArgsConstructor

@Value

@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
{ String name; T value; }}

翻译后:

public final class ValueExample {  private final String name;  private int age;  private final double score;  protected final String[] tags;    @java.beans.ConstructorProperties({"name", "age", "score", "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;  }    @java.lang.Override  public boolean equals(Object o) {    if (o == this) return true;    if (!(o instanceof ValueExample)) return false;    final ValueExample other = (ValueExample)o;    final Object this$name = this.getName();    final Object other$name = other.getName();    if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;    if (this.getAge() != other.getAge()) return false;    if (Double.compare(this.getScore(), other.getScore()) != 0) return false;    if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;    return true;  }    @java.lang.Override  public int hashCode() {    final int PRIME = 59;    int result = 1;    final Object $name = this.getName();    result = result * PRIME + ($name == null ? 43 : $name.hashCode());    result = result * PRIME + this.getAge();    final long $score = Double.doubleToLongBits(this.getScore());    result = result * PRIME + (int)($score >>> 32 ^ $score);    result = result * PRIME + Arrays.deepHashCode(this.getTags());    return result;  }    @java.lang.Override  public String toString() {    return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";  }    ValueExample withAge(int age) {    return this.age == age ? this : new ValueExample(name, age, score, tags);  }    public static final class Exercise
{ private final String name; private final T value; private Exercise(String name, T value) { this.name = name; this.value = value; } public static
Exercise
of(String name, T value) { return new Exercise
(name, value); } public String getName() { return this.name; } public T getValue() { return this.value; } @java.lang.Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof ValueExample.Exercise)) return false; final Exercise
other = (Exercise
)o; final Object this$name = this.getName(); final Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; final Object this$value = this.getValue(); final Object other$value = other.getValue(); if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false; return true; } @java.lang.Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $name = this.getName(); result = result * PRIME + ($name == null ? 43 : $name.hashCode()); final Object $value = this.getValue(); result = result * PRIME + ($value == null ? 43 : $value.hashCode()); return result; } @java.lang.Override public String toString() { return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")"; } }}

我们发现了 @Value 就是 @Data 的不可变版本。至于不可变有什么好处。可有参看此篇(

@Builder

我的最爱

@Builderpublic class BuilderExample {  private String name;  private int age;  @Singular private Set
occupations;}翻译后:public class BuilderExample { private String name; private int age; private Set
occupations; BuilderExample(String name, int age, Set
occupations) { this.name = name; this.age = age; this.occupations = occupations; } public static BuilderExampleBuilder builder() { return new BuilderExampleBuilder(); } public static class BuilderExampleBuilder { private String name; private int age; private java.util.ArrayList
occupations; BuilderExampleBuilder() { } 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
(); } this.occupations.add(occupation); return this; } public BuilderExampleBuilder occupations(Collection
occupations) { if (this.occupations == null) { this.occupations = new java.util.ArrayList
(); } this.occupations.addAll(occupations); return this; } public BuilderExampleBuilder clearOccupations() { if (this.occupations != null) { this.occupations.clear(); } return this; } public BuilderExample build() { Set
occupations = ...; return new BuilderExample(name, age, occupations); } @java.lang.Override public String toString() { return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")"; } }}

builder是现在比较推崇的一种构建值对象的方式。

作者注:生成器模式

@SneakyThrows

to RuntimeException 小助手

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

翻译后

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

很好的隐藏了异常,有时候的确会有这样的烦恼,从某种程度上也是遵循的了 let is crash

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

翻译后

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

这个就比较简单直接添加了synchronized关键字就Ok啦。不过现在JDK也比较推荐的是 Lock 对象,这个可能用的不是特别多。

@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;  }}

翻译后:

public class GetterLazyExample {  private final java.util.concurrent.AtomicReference
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; }}

@Log

再也不用写那些差不多的LOG啦

@Logpublic class LogExample {    public static void main(String... args) {    log.error("Something's wrong here");  }}
@Slf4jpublic class LogExampleOther {    public static void main(String... args) {    log.error("Something else is wrong here");  }}
@CommonsLog(topic="CounterLog")public class LogExampleCategory {  public static void main(String... args) {    log.error("Calling the 'CounterLog' with a message");  }}

翻译后:

public class LogExample {  private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());    public static void main(String... args) {    log.error("Something's wrong here");  }}
public class LogExampleOther {  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);    public static void main(String... args) {    log.error("Something else is wrong here");  }}
public class LogExampleCategory {  private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");  public static void main(String... args) {    log.error("Calling the 'CounterLog' with a message");  }}

Lombok原理

说道 Lombok,我们就得去提到 JSR 269: Pluggable Annotation Processing API () 。JSR 269 之前我们也有注解这样的神器,可是我们比如想要做什么必须使用反射,反射的方法局限性较大。首先,它必须定义@Retention为RetentionPolicy.RUNTIME,只能在运行时通过反射来获取注解值,使得运行时代码效率降低。其次,如果想在编译阶段利用注解来进行一些检查,对用户的某些不合理代码给出错误报告,反射的使用方法就无能为力了。而 JSR 269 之后我们可以在 Javac的编译期利用注解做这些事情。所以我们发现核心的区分是在 运行期 还是 编译期。

从上图可知,Annotation Processing 是在解析和生成之间的一个步骤。

上图是 Lombok 处理流程,在Javac 解析成抽象语法树之后(AST), Lombok 根据自己的注解处理器,动态的修改 AST,增加新的节点(所谓代码),最终通过分析和生成字节码。

关于原理我们大致上的描述下,如果有兴趣可以参考下方文档。

本文作者:yann

原文链接:http://t.cn/RS0UdrX
版权归作者所有,转载请注明出处

你可能感兴趣的文章
C++的模板化等等的确实比C用起来方便多了
查看>>
ROS是不是可以理解成一个虚拟机,就是操作系统之上的操作系统
查看>>
用STL algorithm轻松解决几道算法面试题
查看>>
ACfly之所以不怕炸机因为它觉得某个传感器数据不安全就立马不用了
查看>>
我发觉,不管是弄ROS OPENCV T265二次开发 SDK开发 caffe PX4 都是用的C++
查看>>
ROS的安装(包含文字和视频教程,我的ROS安装教程以这篇为准)
查看>>
国内有个码云,gitee
查看>>
原来我之前一直用的APM固件....现在很多东西明白了。
查看>>
realsense-ros里里程计相关代码
查看>>
似乎写个ROS功能包并不难,你会订阅话题发布话题,加点逻辑处理,就可以写一些基础的ROS功能包了。
查看>>
if __name__ == ‘__main__‘:就是Python里的main函数,脚本从这里开始执行,如果没有main函数则从上到下顺序执行。
查看>>
PX4官方用户和开发手册的首页面是会给你选择英文和中文的
查看>>
网络协议栈我是不是可以这么理解,就是把你要发送的数据自动处理成TCPIP格式的消息发出去,这种底层的转换不需要你弄了。
查看>>
除了LwIP还有uIP
查看>>
《跟工程师学嵌入式开发》这本书最后的终极项目我反而觉得有说头
查看>>
博士的申请考核制
查看>>
MAVLink学习之路05_MAVLink应用编程接口分析(也有讲STM32下的收发函数)
查看>>
找到了中文版的mavlink手册
查看>>
浅谈飞控开发的仿真功能
查看>>
我觉得在室内弄无人机开发装个防撞机架还是很有必要的,TBUS就做得很好。
查看>>