转载 http://t.cn/RS0UdrX

Lombok简介

如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 注解:
@Data :注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
@Setter:注解在属性上;为属性提供 setting 方法
@Getter:注解在属性上;为属性提供 getting 方法
@Log4j :注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
@NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
@AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
@RequiredArgsConstructor: 会生成一个包含常量,和标识了NotNull的变量 的构造方法。生成的构造方法是private,如何想要对外提供使用可以使用staticName选项生成一个static方法。

Lombok安装

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>

编辑器需要安装插件,intellij idea 安装插件 Lombok Plugin

Lombok使用

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

2. @NonNull

使用 @NonNull 注解修饰的字段 通过 set 方法设置时如果为 null, 将抛出 NullPointerException

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

3. @Cleanup

主要用来修饰 IO 流相关类, 会在 finally 代码块中对该资源进行 close();

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

4. @Getter/@Setter

注解在属性上;为属性提供 setting、getting 方法

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

5. @ToString

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

6. @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

@NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
@AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
@RequiredArgsConstructor 为未初始化的 final 字段和使用 @NonNull 标注的字段生成构造函数

@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() {
}
}
}

7. @Data

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

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

8. @Value

@Value 就是 @Data 的不可变版本

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

9. @Builder

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

创建一个静态内部类, 使用该类可以使用链式调用创建对象
如 User 对象中存在 name,age 字段, User user=User.builder().name("姓名").age(20).build()

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

10. @SneakyThrows

对标注的方法进行 try catch 后抛出异常, 可在 value 输入需要 catch 的异常数组, 默认 catch Throwable

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

11. @Synchronized

在标注的方法内 使用 synchronized($lock) {} 对代码进行包裹 ,$lock 为 new Object[0]

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

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

13. @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. lombok 简化java代码注解

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

  2. Lombok简化Java代码

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

  3. Groovy学习:第一章 用Groovy简化Java代码

    1. Groovy的安装 目前Groovy的最新版本为2.1.2版,下载地址为:http://groovy.codehaus.org/Download下载后解压groovy-binary-2.1.2. ...

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

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

  5. EL和 JSTL? 在JSP中简化 java代码的写法!

    一.servlet部分 package com.aaa.servlet; import com.aaa.dao.IStudentDAO; import com.aaa.dao.Impl.Student ...

  6. eclipse使用lombok简化java代码

    可以利用注解来代替getter.setter.toString.hashCode.构造方法等,简化代码开发. 具体用法 https://www.cnblogs.com/qnight/p/8997493 ...

  7. 【转】Lombok:让JAVA代码更优雅

    原文地址:http://blog.didispace.com/java-lombok-1/ 关于Lombok,其实在网上可以找到很多如何使用的文章,但是很少能找到比较齐全的整理.我也一直寻思着想写一篇 ...

  8. Java代码简化神器-Lombok

    一.背景 前段时间在开源社区中发现了一个比较牛逼的简化Java代码的神器-Lombok,接着自己写了demo进行测试和练习,感觉真的很不错,特此分享给需要的小伙伴们~ 二.开发之前的准备 1.lomb ...

  9. 使用 Lombok 简化项目中无谓的Java代码

    在写使用Java时,难免会有一些模板代码要写,不然get/set,toString, hashCode, close 资源,定义构造函数等等.代码会显得很冗余,很长.Lombok项目可以是我们摆脱这些 ...

随机推荐

  1. Sum BZOJ 3944

    Sum [问题描述] 给定一个正整数 N ( N <= 231 - 1 ) 求: [输入格式] 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询 ...

  2. 如果dom节点是动态添加进页面的,在页面节点绑定事件如何解决的问题。

    如果dom节点是动态添加进页面,想在节点绑定事件,传统的做法就是遍历节点,但会出现问题,也肯能有其他的办法,突然想到 可以依据事件冒泡,这样就不惧页面后添加节点而不响应事件的问题.比较结实.示例代码如 ...

  3. C 语言 文件读写

    在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之.一.流式文件操作 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:type ...

  4. Css Position定位(简易版本)

    准备前的知识: 定位只对块级起作用.如div,p等元素是块级元素,如果是内联元素则可以先变成块级元素,display:block即可. 开始讲解: 定位共四种:static,fixed,relativ ...

  5. http://blog.csdn.net/zh521zh/article/details/52687922

    http://blog.csdn.net/zh521zh/article/details/52687922

  6. Android -- native关键字

    native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中.Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口 ...

  7. SQL中Inserted 和Deleted表 以及触发Trigger

    什么是Inserted 和Deleted表 他们有什么用 trigger 的简单实用 1.什么是Inserted 和Deleted表 当插入数据的时候,其实是同时向目的表 和inserted表中插入数 ...

  8. hibernate session缓存

    Session 概述 Session 接口是 Hibernate 向应用程序提供的操纵数据库的最基本的接口, 它提供了基本的保存, 更新, 删除和载入 Java 对象的方法. Session 具有一个 ...

  9. VueJS样式绑定:v-bind

    HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <titl ...

  10. 通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core? .Net Web开发技术栈

    通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core?   什么是.NET?什么是.NET Framework?本文将从上往下,循序渐进的介绍一系列相关.NET的概念 ...