原文地址: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,增加新的节点(所谓代码),最终通过分析和生成字节码。
关于原理我们大致上的描述下,如果有兴趣可以参考下方文档。
- JAVA8-让代码更优雅之List排序
先定义一个实体类 @Data @AllArgsConstructor @NoArgsConstructor public class Human { private String name; priv ...
- JDK8漫谈——代码更优雅
简介 lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method).将Lambda表达式引入JAVA中的动机源于一个叫"行为参数"的模式.这种模式 ...
- lombok 简化java代码注解
lombok 简化java代码注解 安装lombok插件 以intellij ide为例 File-->Setting-->Plugins-->搜索"lombok plug ...
- Lombok简化Java代码
导包:import lombok.Data; Lombok简化Java代码: 在Lombok中,生成构造方法的annotation一共有三个:@NoArgsConstructor, @Required ...
- Lambda表达式, 可以让我们的代码更优雅.
在C#中, 适当地使用Lambda表达式, 可以让我们的代码更优雅. 通过lambda表达式, 我们可以很方便地创建一个delegate: 下面两个语句是等价的 Code highlighting p ...
- CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅
首页 登录注册 CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅 阅读 8113 收藏 927 2017-09-26 原文链接:github.com 腾讯云容器服务CSS,立 ...
- 用Assert(断言)封装异常,让代码更优雅(附项目源码)
有关Assert断言大家并不陌生,我们在做单元测试的时候,看业务事务复合预期,我们可以通过断言来校验,断言常用的方法如下: public class Assert { /** * 结果 = 预期 则正 ...
- 想让你的java代码更漂亮,用枚举吧
枚举是java 5之后添加的一个重要特性,这个特性不能提高性能,但是能让java程序员写出更优雅的代码. 我之前看到过挺多介绍java枚举的不错的帖子,我也来参与以下这个话题. 1. 枚举基本用法 / ...
- Lombok简化Java代码的好工具
lombok 的官方网址:http://projectlombok.org/ 关于lombok 的介绍,有几篇帖子,写得都很好 比如 http://www.blogjava.net/fancydeep ...
随机推荐
- Docker : endpoint with name xxx already exists.
停止不了容器,在尝试过: docker stop [container_id] docker kill [container_id] 都不行之后,强制删除容器: docker rm -f [cont ...
- Elasticsearch与RDS比较
Elasticsearch是一个分布式,实时,全文搜索引擎.所有操作都是通过RESTful接口实现,其底层实现是基于Lucene全文搜索引擎.数据以JSON文档的格式存储索引,不需要预先规定范式. 和 ...
- MySQL子查询的优化
本文基于MySQL5.7.19测试 创建四张表,pt1.pt2表加上主键 mysql> create table t1 (a1 int, b1 int); mysql> create ta ...
- C++的字符串格式化库
这里向大家介绍一个C++的字符串格式化库,叫cpptempl,这个库支持对字符串格式的条件,循环,变量插入.看上去很不错,只不过其是基于boost库的. 下面是一个例子: 1 2 3 4 5 6 7 ...
- js html 页面倒计时 精确到秒
<!doctype html> <html> <head> <meta charset="utf-8"> </head> ...
- 使用C#WebClient类访问(上传/下载/删除/列出文件目录)
在使用WebClient类之前,必须先引用System.Net命名空间,文件下载.上传与删除的都是使用异步编程,也可以使用同步编程, 这里以异步编程为例: 1)文件下载: static void Ma ...
- iOS常用RGB颜色的色值表
常用RGB颜色表 R G B 值 R G B 值 R G B 值 黑色 0 0 0 #000000 黄色 255 255 0 #FFFF00 浅灰蓝色 176 224 230 #B0E0E6 象牙黑 ...
- Java批量插入更新操作
以前总是说批量插入和更新的效率比非批量的要高,但是一直没有使用过批量处理数据的功能,现在由于项目中需要处理的数据量比较大,所以使用了批量处理的功能,java代码如下: 1.java实现批量插入数据: ...
- Netflix OSS、Spring Cloud还是Kubernetes? 都要吧!
Netflix OSS是由Netflix公司主持开发的一套代码框架和库,目的是解决上了规模之后的分布式系统可能出现的一些有趣问题.对于当今时代的Java开发者们来说,Netflix OSS简直就是在云 ...
- jQuery学习笔记(jquery.ui插件)
官网地址:http://ui.jquery.com/ jQuery UI源自于一jQuery插件-Interface.目前版本是1.10.3,需要jQuery 1.6以上版本支持. jQuery UI ...