原文地址:http://blog.didispace.com/java-lombok-1/

关于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包,可到这里下载:https://projectlombok.org/download

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

Eclipse (含延伸版本)

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

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

IntelliJ IDEA

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

更多安装请参考:https://projectlombok.org/

Lombok使用

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

val

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

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

翻译成 Java 程序是:

public String example() {
final ArrayList<String> example = new ArrayList<String>();
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<T> {
private int x, y;
@NonNull private T description; @NoArgsConstructor
public static class NoArgsExample {
@NonNull private String field;
}
}

翻译后:

public class ConstructorExample<T> {
private int x, y;
@NonNull private T description; private ConstructorExample(T description) {
if (description == null) throw new NullPointerException("description");
this.description = description;
} public static <T> ConstructorExample<T> of(T description) {
return new ConstructorExample<T>(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<T> {
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<T> { private final String name; private final T value; private Exercise(String name, T value) { this.name = name; this.value = value; } public static <T> Exercise<T> of(String name, T value) { return new Exercise<T>(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 的不可变版本。至于不可变有什么好处。可有参看此篇(https://blogs.msdn.microsoft.com/ericlippert/2007/11/13/immutability-in-c-part-one-kinds-of-immutability/)

@Builder

我的最爱

@Builder
public class BuilderExample {
private String name;
private int age;
@Singular private Set<String> occupations;
}
翻译后: public class BuilderExample {
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;
} public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
} public static class BuilderExampleBuilder {
private String name;
private int age;
private java.util.ArrayList<String> 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<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.
// go to https://projectlombok.org/features/Singular-snippet.html to see it.
Set<String> 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<java.lang.Object> cached = new java.util.concurrent.AtomicReference<java.lang.Object>(); 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啦

@Log
public class LogExample { public static void main(String... args) {
log.error("Something's wrong here");
}
}
@Slf4j
public 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 (https://www.jcp.org/en/jsr/detail?id=269) 。JSR 269 之前我们也有注解这样的神器,可是我们比如想要做什么必须使用反射,反射的方法局限性较大。首先,它必须定义@Retention为RetentionPolicy.RUNTIME,只能在运行时通过反射来获取注解值,使得运行时代码效率降低。其次,如果想在编译阶段利用注解来进行一些检查,对用户的某些不合理代码给出错误报告,反射的使用方法就无能为力了。而 JSR 269 之后我们可以在 Javac的编译期利用注解做这些事情。所以我们发现核心的区分是在 运行期 还是 编译期。

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

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

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

【转】Lombok:让JAVA代码更优雅的更多相关文章

  1. JAVA8-让代码更优雅之List排序

    先定义一个实体类 @Data @AllArgsConstructor @NoArgsConstructor public class Human { private String name; priv ...

  2. JDK8漫谈——代码更优雅

    简介 lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method).将Lambda表达式引入JAVA中的动机源于一个叫"行为参数"的模式.这种模式 ...

  3. lombok 简化java代码注解

    lombok 简化java代码注解 安装lombok插件 以intellij ide为例 File-->Setting-->Plugins-->搜索"lombok plug ...

  4. Lombok简化Java代码

    导包:import lombok.Data; Lombok简化Java代码: 在Lombok中,生成构造方法的annotation一共有三个:@NoArgsConstructor, @Required ...

  5. Lambda表达式, 可以让我们的代码更优雅.

    在C#中, 适当地使用Lambda表达式, 可以让我们的代码更优雅. 通过lambda表达式, 我们可以很方便地创建一个delegate: 下面两个语句是等价的 Code highlighting p ...

  6. CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅

    首页   登录注册         CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅 阅读 8113 收藏 927 2017-09-26 原文链接:github.com 腾讯云容器服务CSS,立 ...

  7. 用Assert(断言)封装异常,让代码更优雅(附项目源码)

    有关Assert断言大家并不陌生,我们在做单元测试的时候,看业务事务复合预期,我们可以通过断言来校验,断言常用的方法如下: public class Assert { /** * 结果 = 预期 则正 ...

  8. 想让你的java代码更漂亮,用枚举吧

    枚举是java 5之后添加的一个重要特性,这个特性不能提高性能,但是能让java程序员写出更优雅的代码. 我之前看到过挺多介绍java枚举的不错的帖子,我也来参与以下这个话题. 1. 枚举基本用法 / ...

  9. Lombok简化Java代码的好工具

    lombok 的官方网址:http://projectlombok.org/ 关于lombok 的介绍,有几篇帖子,写得都很好 比如 http://www.blogjava.net/fancydeep ...

随机推荐

  1. SQL表之间复制数据、选出随机几条数据、删除重复数据、取得自增长列等操作

    --表之间数据复制 SELECT* INTO yozhu FROM yo --复制一份表 SELECT* INTO yozhu1 FROM yo where 1<>1 --只复制表结构,无 ...

  2. 《JAVA与模式》之备忘录模式

    一.备忘录(Memento)模式结构 备忘录对象是一个用来存储另外一个对象内部状态的快照(snapshot)的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来, ...

  3. JDBC连接SQLServer出现的异常

    数据库连接.  question1. java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver 异常 ...

  4. Redis快速入门及应用

    Redis的使用难吗?不难,Redis用好容易吗?不容易.Redis的使用虽然不难,但与业务结合的应用场景特别多.特别紧,用好并不容易.我们希望通过一篇文章及Demo,即可轻松.快速入门并学会应用.一 ...

  5. SharePoint下在Feature中动态Register/Remove HttpModule

    在SharePoint开发时,你会遇到这样一个问题,Global.asax去哪儿?怎样添加一个Global.asax?怎样在Application_Start这个事件处理程序里设置初始化?似乎在Vis ...

  6. Java Nashorn--Part 6

    Nashorn 的 JavaScript 语言的扩展 正如我们所讨论的,Nashorn 是一个完全符合 ECMAScript 5.1 的实现.然而除此之外,Nashorn 还实现了很多 JavaScr ...

  7. 类名.class和getClass()区别

    class叫做“类字面量”,因class是关键字, 所以class编译时确定,getclass()运行时根据实际实例确定.String.class 是能对类名的引用取得在内存中该类型class对象的引 ...

  8. 使用Python3自带工具2to3.py 转换 Python2.x 代码 到Python3

    几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为了简化这个转换过程,Python 3自带了一个叫做2to3的实用脚本(Utility Script),这个脚本会 ...

  9. ASP.NET 的ClientIDMode属性

    在ASP.NET 4.0之前我们总是要为控件的ClientID头疼,比如明明一个叫lblName的Label放在一个叫做grd的GridView里面后,在页面上改Label的ID就变成了诸如grd_c ...

  10. Android后台处理最佳实践(Best Practices for Background Jobs)

    本课将告诉你如何通过后台加载来加速应用启动和降低应用耗电. 后台跑服务 除非你做了特殊指定,否则在应用中的大部分前台操作都是在一个特殊的UI线程里面进行的.这有可能会导致一些问题,因为长时间运行的操作 ...