Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Lombok,简化代码的神器,你值得拥有

Lombok,简化代码的神器,你值得拥有

作者头像
孟君
发布于 2019-08-26 09:02:13
发布于 2019-08-26 09:02:13
1.6K00
代码可运行
举报
运行总次数:0
代码可运行

本文给大家介绍一个Java代码简化的神器 -- Lombok。主要从如下几个方面进行展开:

  1. Lombok介绍
  2. Lombok安装
  3. Lombok注解使用
  4. Lombok原理解析
  5. 小结

1、Lombok介绍

根据Lombok官网https://projectlombok.org/的介绍如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Project Lombok is a java library that automatically plugs into 
your editor and build tools, spicing up your java.
Never write another getter or equals method again, 
with one annotation your class has a fully featured builder, 
Automate your logging variables, and much more.

根据Lombok官网的描述可以看出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Project Lombok是一个java库,其可以自动插入到你的编辑器和构建工具中,
使java代码更加生动。
使用Lombok提供的注解将会带来诸多改变,如:
 -- 不需要再写getter、equals等方法
 -- 一个注解将为类提供功能齐全的Builder,后续我们将会演示@Builder注解
 -- 自动插入日志变量等等

看着还挺吸引人吧,那接下来就来安装一下,然后来小试一下其提供的神奇注解。

2、Lombok安装

访问Lombok官网(https://projectlombok.org/download)下载Lombok.jar。使用java -jar lombok.jar运行, 选择指定IDE路径,本文以Eclipse为示例,其它IDE的安装类似。选择Eclipse.exe。

点击Install / update按钮即可完成安装。

3、Lombok注解使用

引入Lombok依賴包:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>

Lombok提供的注解可以在lombok的package找到,如下图所示:

本文将给出如下注解的使用示例,包括:

  1. @Getter @Setter
  2. @NoArgsConstructor AllArgsConstructor
  3. @EqualsAndHashCode
  4. @ToString
  5. @Data
  6. @NonNull
  7. @Builder
  8. @Singular
  9. @CleanUp
  10. @Synchronized
  11. @Slf4j

3.1 @Getter / @Setter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.Serializable;
import java.util.List;

import lombok.Getter;
import lombok.Setter;

@Getter 
@Setter
public class Book implements Serializable  {

  private static final long serialVersionUID = -8212889116567064704L;
  
  /**书名*/
  private String name;
  
  /**ISBN*/
  private  String isbn;
  
  /**作者*/
  private List<String> authors;
  
}

代码自动为各个属性增加了getter、setter方法,如下图所示:

利用反编译工具查看,其效果等价于如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.Serializable;
import java.util.List;

public class Book
  implements Serializable
{

  private static final long serialVersionUID = 0x8e05f4dcbb592f80L;
  private String name;
  private String isbn;
  private List authors;

  public Book()
{
  }

  public String getName()
{
    return name;
  }

  public String getIsbn()
{
    return isbn;
  }

  public List getAuthors()
{
    return authors;
  }

  public void setName(String name)
{
    this.name = name;
  }

  public void setIsbn(String isbn)
{
    this.isbn = isbn;
  }

  public void setAuthors(List authors)
{
    this.authors = authors;
  }
}

3.2 @NoArgsConstructor @AllsConstructor

从注解的名字上就可以看出,其作用是产生无参以及包含全部参数的构造函数,如下图高亮部分所示:

如果,Book类需要增加一个出版社press的属性,那么,全部参数的构造函数需要重新添加一个属性。在这个时候,使用@AllArgsConstructor注解的BookLombok 类将不用再修改任何代码。

3.3 @EqualsAndHashCode

该注解将为类产生equals,hasCode,其中还产生了一个用于比较的canEquals方法,如下图高亮部分所示:

反编译后增加的代码如所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

  public boolean equals(Object o)
  {
    if (o == this)
      return true;
    if (!(o instanceof Book))
      return false;
    Book other = (Book)o;
    if (!other.canEqual(this))
      return false;
    Object this$name = getName();
    Object other$name = other.getName();
    if (this$name != null ? !this$name.equals(other$name) : other$name != null)
      return false;
    Object this$isbn = getIsbn();
    Object other$isbn = other.getIsbn();
    if (this$isbn != null ? !this$isbn.equals(other$isbn) : other$isbn != null)
      return false;
    Object this$authors = getAuthors();
    Object other$authors = other.getAuthors();
    return this$authors != null ? this$authors.equals(other$authors) : other$authors == null;
  }

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

  public int hashCode()
  {
    int PRIME = 59;
    int result = 1;
    Object $name = getName();
    result = result * 59 + ($name != null ? $name.hashCode() : 43);
    Object $isbn = getIsbn();
    result = result * 59 + ($isbn != null ? $isbn.hashCode() : 43);
    Object $authors = getAuthors();
    result = result * 59 + ($authors != null ? $authors.hashCode() : 43);
    return result;
  }

3.4 @ToString

该注解将为类产生toString方法,如下图高亮部分所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  public String toString()
  {
    return (new StringBuilder("Book(name=")).append(getName()).append(", isbn=").append(getIsbn()).append(", authors=").append(getAuthors()).append(")").toString();
  }

3.5 @Data

使用@Data注解,其效果等价于:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
All together now: A shortcut for
@ToString, @EqualsAndHashCode, 
@Getter on all fields, and @Setter on all non-final fields, 
and @RequiredArgsConstructor!
  • 添加@ToString, @EqualsAndHashCode 和 @RequiredArgsConstructor
  • 所有变量增加@Getter
  • 所有非final类型的变量增加@Setter

只有一个@Data注解的类如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.Serializable;
import java.util.List;

import lombok.Data;

@Data 
public class Book implements Serializable  {

  private static final long serialVersionUID = -8212889116567064704L;
  
  /**书名*/
  private String name;
  
  /**ISBN*/
  private  String isbn;
  
  /**作者*/
  private List<String> authors;
  
}

反编译查看一下,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.Serializable;
import java.util.List;

public class Book
  implements Serializable
{

  private static final long serialVersionUID = 0x8e05f4dcbb592f80L;
  private String name;
  private String isbn;
  private List authors;

  public String getName()
{
    return name;
  }

  public String getIsbn()
{
    return isbn;
  }

  public List getAuthors()
{
    return authors;
  }

  public void setName(String name)
{
    this.name = name;
  }

  public void setIsbn(String isbn)
{
    this.isbn = isbn;
  }

  public void setAuthors(List authors)
{
    this.authors = authors;
  }

  public boolean equals(Object o)
{
    if (o == this)
      return true;
    if (!(o instanceof Book))
      return false;
    Book other = (Book)o;
    if (!other.canEqual(this))
      return false;
    Object this$name = getName();
    Object other$name = other.getName();
    if (this$name != null ? !this$name.equals(other$name) : other$name != null)
      return false;
    Object this$isbn = getIsbn();
    Object other$isbn = other.getIsbn();
    if (this$isbn != null ? !this$isbn.equals(other$isbn) : other$isbn != null)
      return false;
    Object this$authors = getAuthors();
    Object other$authors = other.getAuthors();
    return this$authors != null ? this$authors.equals(other$authors) : other$authors == null;
  }

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

  public int hashCode()
{
    int PRIME = 59;
    int result = 1;
    Object $name = getName();
    result = result * 59 + ($name != null ? $name.hashCode() : 43);
    Object $isbn = getIsbn();
    result = result * 59 + ($isbn != null ? $isbn.hashCode() : 43);
    Object $authors = getAuthors();
    result = result * 59 + ($authors != null ? $authors.hashCode() : 43);
    return result;
  }

  public String toString()
{
    return (new StringBuilder("Book(name=")).append(getName()).append(", isbn=").append(getIsbn()).append(", authors=").append(getAuthors()).append(")").toString();
  }

  public Book()
{
  }
}

可以看到所有属性的Getter、Setter、默认构造函数、toString方法、equas和hasCode方法都具备了。

3.6 @NonNull

此注解用于标注属性不能为null,如果setter方法传值为null,则抛出NullpointerException。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.Serializable;
import java.util.List;

import lombok.Data;
import lombok.NonNull;

@Data 
public class Book implements Serializable  {

  private static final long serialVersionUID = -8212889116567064704L;
  
  /**书名*/
  private @NonNull String name;
  
  /**ISBN*/
  private  String isbn;
  
  /**作者*/
  private List<String> authors;
  
}

上述示例对name增加了@NonNull, 反编译后,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  public void setName(String name)
  {
    if (name == null)
    {
      throw new NullPointerException("name is marked non-null but is null");
    } else
    {
      this.name = name;
      return;
    }
  }

3.7 @Builder

此注解将产生Builder类,可以采用构建者模式完成赋值,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Getter
@Setter
@Builder
public class Book implements Serializable  {

  private static final long serialVersionUID = -8212889116567064704L;
  
  /**书名*/
  private String name;
  
  /**ISBN*/
  private  String isbn;
  
  /**作者*/
  private List<String> authors;
  
}

可以看到使用@Builder之后,自动生成了BookBuilder类和build方法, 如下图高亮部分所示:

反编译后,其效果如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.Serializable;
import java.util.List;

public class Book
  implements Serializable
{
  public static class BookBuilder
{

    private String name;
    private String isbn;
    private List authors;

    public BookBuilder name(String name)
{
      this.name = name;
      return this;
    }

    public BookBuilder isbn(String isbn)
{
      this.isbn = isbn;
      return this;
    }

    public BookBuilder authors(List authors)
{
      this.authors = authors;
      return this;
    }

    public Book build()
{
      return new Book(name, isbn, authors);
    }

    public String toString()
{
      return (new StringBuilder("Book.BookBuilder(name=")).append(name).append(", isbn=").append(isbn).append(", authors=").append(authors).append(")").toString();
    }

    BookBuilder()
    {
    }
  }


  private static final long serialVersionUID = 0x8e05f4dcbb592f80L;
  private String name;
  private String isbn;
  private List authors;

  Book(String name, String isbn, List authors)
  {
    this.name = name;
    this.isbn = isbn;
    this.authors = authors;
  }

  public static BookBuilder builder()
{
    return new BookBuilder();
  }

  public String getName()
{
    return name;
  }

  public String getIsbn()
{
    return isbn;
  }

  public List getAuthors()
{
    return authors;
  }

  public void setName(String name)
{
    this.name = name;
  }

  public void setIsbn(String isbn)
{
    this.isbn = isbn;
  }

  public void setAuthors(List authors)
{
    this.authors = authors;
  }
}

Buider创建对象示例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

    Book book = Book.builder().name("Eric").isbn("1234567890")
                              .authors(Arrays.asList("Eric","Joan")).build();
   

3.8 @Singular

此注解与@Builder一起使用,增加单个赋值的方法,如对作者Authors变量设置此变量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Getter
@Setter
@Builder
public class Book implements Serializable  {

  private static final long serialVersionUID = -8212889116567064704L;
  
  /**书名*/
  private String name;
  
  /**ISBN*/
  private  String isbn;
  
  /**作者*/
  private @Singular List<String> authors;
  
}

Builder支持单个author的赋值,增加一个方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   public BookBuilder author(String author)
    {
      if (authors == null)
        authors = new ArrayList();
      authors.add(author);
      return this;
    }

这样时候,Authors列表的赋值,支持一个一个地增加,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Book book = Book.builder().name("Eric").isbn("1234567890asdfghjkl")
                          .author("Eirc")
                          .author("Joan")
                          .build();

3.9 @CleanUp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
使用@CleanUp可以完成自动资源管理,如添加close()方法关闭资源。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import lombok.Cleanup;
import java.io.*;

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

等价于

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.io.*;

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

3.10 @Synchronized

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 For non-static methods, a field named {@code $lock} is used, 
 and for static methods, {@code $LOCK} is used. 

从@Synchronized注解描述可以看出,其对非静态方法会使用变量$lock,而对静态方法使用的是$LOCK。如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SynchronizedExample {

  private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");
   
  @Synchronized
  public String synchronizedFormat(Date date) {
      return format.format(date);
  }
  
  @Synchronized
  public static  String synchronizedStaticMethod() {
    
    String message = "hello synchronized";
      return  message;
  }
}

从下图右侧的高亮部分可以看到包含了对象$lock 和 $LOCK。

反编译查看代码,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SynchronizedExample
{

  private final Object $lock = new Object[0];
  private static final Object $LOCK = new Object[0];
  private DateFormat format;

  public SynchronizedExample()
  {
    format = new SimpleDateFormat("MM-dd-YYYY");
  }

  public String synchronizedFormat(Date date)
  {
    Object obj = $lock;
    JVM INSTR monitorenter ;
    return format.format(date);
    obj;
    JVM INSTR monitorexit ;
    throw ;
  }

  public static String synchronizedStaticMethod()
  {
    Object obj = $LOCK;
    JVM INSTR monitorenter ;
    String message = "hello synchronized";
    return message;
    obj;
    JVM INSTR monitorexit ;
    throw ;
  }

}

上述的moniterenter和moniterexit其实就是synchronized的实现,所以代码也就等价于:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SynchronizedExample
{

  private final Object $lock = new Object[0];
  private static final Object $LOCK = new Object[0];
  private DateFormat format;

  public SynchronizedExample()
  {
    format = new SimpleDateFormat("MM-dd-YYYY");
  }

  public String synchronizedFormat(Date date)
  {
     synchronized($lock) {
        return format.format(date);
     }
  }

  public static String synchronizedStaticMethod()
  {
    synchronized($LOCK) {
      String message = "hello synchronized";
      return message;
    }
  }

}

3.11@Slf4j

使用@Slf4j,其会在代码增加一个log对象,我们直接可以使用log进行日志记录。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LogExample {

    public void greeting(String name) {
        System.out.println("Hello," +name);
        log.info("Method greeting, name is {}", name);
    }
    
    public static void main(String[] args) {
      LogExample example = new LogExample();
      example.greeting("mengjun");
      
  }

}

其等价于:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wangmengjun.tutorial.lombok;

import java.io.PrintStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogExample
{

  private static final Logger log = LoggerFactory.getLogger(com/wangmengjun/tutorial/lombok/LogExample);

  public LogExample()
{
  }

  public void greeting(String name)
{
    System.out.println((new StringBuilder("Hello,")).append(name).toString());
    log.info("Method greeting, name is {}", name);
  }

  public static void main(String args[])
{
    LogExample example = new LogExample();
    example.greeting("mengjun");
  }

}

运行LogEample类,可以直接可以使用log日志记录,可以说非常方便。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Hello,mengjun
10:49:33.765 [main] INFO com.wangmengjun.tutorial.lombok.LogExample - Method greeting, name is mengjun

注意,使用相关的日志注解,需要导入相关的日志,本示例中采用的SLF4j,需要引入如下依赖包:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
 
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

当然,Lombok支持其它日志的记录,如Apache Common, JBOSS、Log4j等,只要使用对应的注解即可。

@CommonsLog

创建

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@JBossLog

创建

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);

@Log

创建

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j

创建

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2

创建

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class

Lombok还提供了很多其它的注解,在本篇文章中就不一一列举出来了。

那么问题来了,既然Lombok有这么好用的功能,其实现的原理又是什么呢?

4、Lombok原理分析

4.1 Java源码编译

在弄清Lombok是如何工作的之前,我们先来看一下OpenJDK上对Java源码编译过程的一个说明:

http://openjdk.java.net/groups/compiler/doc/compilation-overview/index.html

Java 源码编译一般可以分成三个不同的阶段:

  • 解析和输入
  • 注解处理
  • 语义分析和生成class文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
在解析和输入阶段,编译器会解析源文件到一个抽象语法树( Abstract Syntax Tree, 简称AST)。如果语法不合法将会抛出错误。

在注解处理阶段,自定义的注解处理器将会被调用,这可以被认为是预编译阶段。注解处理器可以做一些譬如验证类正确性、产生新的资源包含源文件等操作。

如果新的源码文件是注解处理的结果,那么编译循环回到解析和输入阶段,重复这个过程,直到没有新的源文件生产为止。

在最后一个阶段,即对抽象语法树(AST) 进行语义分析,编译器根据产生的抽象语法树生成class文件(字节码文件)。

大致了解了Java源码编译的过程之后,我们再来看一下Lombok是如何做的?

4.2 Lombok基本原理

Lombok的魔法就在于其修改了AST,分析和生成class阶段使用了修改后的AST,也就最终改变了生成的字节码文件。如,添加一个方法节点 ( Method Node )到AST,那么产生的class文件时将会包含新的方法。

通过修改AST,Lombok可以产生新的方法(如getter、setter等),或者注入代码到已存在的方法中去,比如 ( Lombok 提供的@Cleanup注解 -- 这个可以本文示例中找到 )。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Project Lombok使用了JSR 269 Pluggable Annotation Processing API ,
lombok.jar 包含一个名字为 
/META-INF/services/javax.annotation.processing.Processor的文件。
当 javac 看到编译路径上的这个文件时,
会在编译期间使用定义在这个文件中的注解处理器。

https://www.jcp.org/en/jsr/detail?id=269

定义的注解处理器主要有两个AnnotationProcessor以及ClaimingProcessor。

AnnotationProcessor以及ClaimingProcessor在Lombok中的源代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package lombok.launch;

import java.lang.reflect.Field;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Completion;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;

import sun.misc.Unsafe;

class AnnotationProcessorHider {

    //省略其它
    public static class AnnotationProcessor extends AbstractProcessor {
    private final AbstractProcessor instance = createWrappedInstance();
    
    @Override public Set<String> getSupportedOptions() {
      return instance.getSupportedOptions();
    }
    
    @Override public Set<String> getSupportedAnnotationTypes() {
      return instance.getSupportedAnnotationTypes();
    }
    
    @Override public SourceVersion getSupportedSourceVersion() {
      return instance.getSupportedSourceVersion();
    }
    
    @Override public void init(ProcessingEnvironment processingEnv) {
      disableJava9SillyWarning();
      AstModificationNotifierData.lombokInvoked = true;
      instance.init(processingEnv);
      super.init(processingEnv);
    }
    
    // sunapi suppresses javac's warning about using Unsafe; 'all' suppresses eclipse's warning about the unspecified 'sunapi' key. Leave them both.
    // Yes, javac's definition of the word 'all' is quite contrary to what the dictionary says it means. 'all' does NOT include 'sunapi' according to javac.
    @SuppressWarnings({"sunapi", "all"})
    private void disableJava9SillyWarning() {
      // JVM9 complains about using reflection to access packages from a module that aren't exported. This makes no sense; the whole point of reflection
      // is to get past such issues. The only comment from the jigsaw team lead on this was some unspecified mumbling about security which makes no sense,
      // as the SecurityManager is invoked to check such things. Therefore this warning is a bug, so we shall patch java to fix it.
      
      try {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe u = (Unsafe) theUnsafe.get(null);
        
        Class<?> cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
        Field logger = cls.getDeclaredField("logger");
        u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
      } catch (Throwable t) {
        // We shall ignore it; the effect of this code failing is that the user gets to see a warning they remove with various --add-opens magic.
      }
    }
    
    @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
      return instance.process(annotations, roundEnv);
    }
    
    @Override public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
      return instance.getCompletions(element, annotation, member, userText);
    }
    
    private static AbstractProcessor createWrappedInstance() {
      ClassLoader cl = Main.getShadowClassLoader();
      try {
        Class<?> mc = cl.loadClass("lombok.core.AnnotationProcessor");
        return (AbstractProcessor) mc.getDeclaredConstructor().newInstance();
      } catch (Throwable t) {
        if (t instanceof Error) throw (Error) t;
        if (t instanceof RuntimeException) throw (RuntimeException) t;
        throw new RuntimeException(t);
      }
    }
  }
  
  @SupportedAnnotationTypes("lombok.*")
  public static class ClaimingProcessor extends AbstractProcessor {
    @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
      return true;
    }
    
    @Override public SourceVersion getSupportedSourceVersion() {
      return SourceVersion.latest();
    }
  }
}

Project Lombok充当了一个注解处理器的角色。注解处理器扮演了一个分发器,其委托Lombok注解处理器来处理,Lombok注解处理器声明了具体要处理的注解。当委托给一个处理器时,Lombok注解处理器会通过注入新的节点(如,方法、表达式等)的方式去修改抽象语法树 (AST)。在注解处理阶段之后,编译器会根据修改后的AST,生成字节码。

Lombok在源码编译中,大致处理的过程如下图所示:

图片来源:http://notatube.blogspot.jp/2010/12/project-lombok-creating-custom.html

5、小结

本文先对Lombok进行了介绍,大致理解其是做什么用的。然后给出安装步骤,结合示例对多个注解进行简单说明,相信经过这些例子的说明,读者已经有了一个更好的体感,建议亲手操作一下,效果更佳;最后,对Lombok的原理进行了简单分析,可以更好地理解Lombok。

任何事物都具有两面性。尽管,Lombok能带给我们诸多方便,可以减少诸如Getter、 Setter代码,其中@Builder可以采用构建者模式的方式对变量进行赋值,直观方便;@CleanUp可以防止程序忘关闭流等等。但是,在某些场景,其也存在使用的限制,也存在一些缺点,请访问如下链接查看https://code.google.com/p/projectlombok/issues/list。

Lombok也可以在诸多互联网公司的开源代码中看到,大家可以根据自身的需要进行选择。

另外,友情提示一下:如果你的项目组是需要统计代码量,建议还是不要用了 你懂得

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
还在new对象吗?Builder构建对象了解一下?
在平时开发中,我们经常需要去new一个对象。如果一个类的属性很多,就要设置较多的setXXX,这样实例化和赋值分开,较为分散。
孟君
2020/02/25
2.5K0
一个通用的 Builder构建器写法
在平时开发中,Builder方式采用的流式对象创建,我们经常用到,比如Guava的CacheBuilder,如:
孟君
2022/11/21
4420
【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题
Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的Java模型对象(POJO)。在开发环境中使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。
YourBatman
2019/09/03
3.3K0
【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题
99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!
  99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!
不会飞的小鸟
2020/03/30
6550
lombok系列2:lombok注解详解
看到第一篇《初识lombok》你可能意犹未尽,本文我们按照场景来介绍一下常用的注解。
pollyduan
2019/11/04
1.1K0
Java创建对象的几种方法
如果要调用clone方法,那么该object需要实现Cloneable接口,并重写clone()方法。
孟君
2019/10/22
1.2K0
Serializable和Externalizable浅析
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。从而达到网络传输、本地存储的效果。
孟君
2019/08/26
5600
Serializable和Externalizable浅析
最全一篇Lombok使用讲解,及原理,真香啊
Lombok 是一款好用顺手的工具,就像 Google Guava 一样。可用来帮助开发人员消除 Java 的冗长代码,尤其是对于简单的 Java 对象(POJO)。它通过注释实现这一目的。
公众号 IT老哥
2020/09/16
13.3K0
最全一篇Lombok使用讲解,及原理,真香啊
Java开发神器Lombok的安装与使用
项目中经常使用bean,entity等类,绝大部分数据类类中都需要get、set、toString、equals和hashCode方法,虽然eclipse和idea开发环境下都有自动生成的快捷方式,但自动生成这些代码后,如果bean中的属性一旦有修改、删除或增加时,需要重新生成或删除get/set等方法,给代码维护增加负担。而使用了lombok则不一样,使用了lombok的注解(@Setter,@Getter,@ToString,@@RequiredArgsConstructor,@EqualsAndHashCode或@Data)之后,就不需要编写或生成get/set等方法,很大程度上减少了代码量,而且减少了代码维护的负担。故强烈建议项目中使用lombok,去掉bean中get、set、toString、equals和hashCode等方法的代码。
秃头哥编程
2019/06/17
6000
Java开发神器Lombok的安装与使用
加倍提升开发效率,继续深挖Lombok的使用
本篇来接续上一篇文章 这些极简的注解你都清楚吗,主要介绍一下 Lombok 非常用注解。
cxuan
2019/08/09
7920
加倍提升开发效率,继续深挖Lombok的使用
优雅的JAVA工具库LOMBOK
最近在公司的项目中看到了对于Lombok的应用,通过@Data注解标注POJO,省略了大量的getter/setter代码,原先冗长的POJO在瘦身之后直接变得干净、清爽,程序员再也不需要去关注那些长长的方法,只需要集中注意力于字段field之中
java架构师
2019/01/03
5780
Java 之 Lombok 必知必会
在目前众多编程语言中,Java 语言的表现还是抢眼,不论是企业级服务端开发,还是 Andorid 客户端开发,都是作为开发语言的首选,甚至在大数据开发领域,Java 语言也能占有一席之地,如 Hadoop,Spark,Flink 大数据等。而作为已经诞生 24 年的 Java 相比其他语言来说,编写起来略显得冗长和复杂,而为了能极大提升 Java 开发的效率和代码简洁性,一个 Java 库 Lombok 就这样诞生了。
闻人的技术博客
2019/09/19
9520
Java 之 Lombok 必知必会
第十三节:使用Lombok简化你的代码
TOC 在开发过程中,通常都会定义大量的JavaBean,然后通过IDE去产生其属性的构造器、getter、setter、equals、hashcode、toString方法,当要增加属性或者对某个属性进行改变时,比如命名、类型等,都需要重新去产生上面提到的这些方法。这样重复的劳动没有任何意义,Lombok里面的注解可以轻松解决这些问题。 官方地址:https://projectlombok.org/ github地址:https://github.com/rzwitserloot/lombok lombo
入门笔记
2022/02/18
5660
第十三节:使用Lombok简化你的代码
lombok让你提高代码整洁度的神器附教程及原理分析
在Java编程的过程中,我们在Code Entity的时候通常使用 IDE的generator来生成 get set toSting equals hashcode Constructor 等方法,有了lombok以后就不会了,它会在编译的过程中,分析AST抽象语法树的方式,把这些方法插入到编译以后的代码当中,这样做的好处可以降低代码量,让代码变得更容易读 程序源码 @Data public class User { int id; String name; } 编译后的代码 public
Albert陈凯
2018/04/03
7550
Lombok详解
1. Lombok简介 官网地址:https://projectlombok.org/ Lombok项目是一个Java库,它会自动插入您的编辑器和构建工具中,从而为你优化Java代码。 所以可以不用再手写一个getter、setter或equals方法。 2. 变量使用介绍 2.1 val修饰变量 可以使用val作为局部变量声明的类型,而不用实际编写该类型。 当您执行此操作时,将从初始值设定项表达式中推断出类型。 局部变量也将成为final类型的变量。 此功能仅适用于局部变量和foreach循环,不适用于字
牧晗
2020/06/05
1.3K0
Lombok详解
今天 1024,为了不 996,Lombok 用起来以及避坑指南
Lombok 项目是一个 Java 库,它会自动插入编辑器和构建工具中,Lombok 提供了一组有用的注解,用来消除 Java 类中的大量样板代码。
双鬼带单
2020/10/29
8340
简化开发|Lombok神器带你消除冗余代码
Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务过程中冗余的代码,尤其是简单的Java模型对象(POJO)。而当我们如果在开发环境中使用Lombok开发插件后,可以省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生产这些方法,并没有如反射那样降低程序的性能。本文将带大家详细介绍关于Lombok的使用以及原理。
浅羽技术
2020/12/07
5800
简化开发|Lombok神器带你消除冗余代码
一份不可多得的 Lombok 学习指南
Lombok 是一款 Java 开发插件,使得 Java 开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的 Java 模型对象(POJO)。在开发环境中使用 Lombok 插件后,Java 开发人员可以节省出重复构建,诸如 hashCode 和 equals 这样的方法以及各种业务对象模型的 accessor 和 toString 等方法的大量时间。对于这些方法,Lombok 能够在编译源代码期间自动帮我们生成这些方法,但并不会像反射那样降低程序的性能。
阿宝哥
2019/11/06
9990
一份不可多得的 Lombok 学习指南
Java开发的效率工具--Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more. ######################################################## 大概的意思:Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量。
框架师
2020/07/09
7800
Java开发的效率工具--Lombok
二.SpringBoot配置lombok
Lombok想要解决了的是在我们实体Bean中大量的Getter/Setter方法,以及toString, hashCode等可能不会用到,但是某些时候仍然需要复写,以期方便使用的方法;在使用Lombok之后,将由其来自动帮你实现代码生成,注意,其是 在运行过程中,帮你自动生成的 。就是说,将极大减少你的代码总量。提高代码编写的效率。消除模板代码getter、setter、构造器、toString()、equals()便捷的生成比较复杂的代码,例如一个entity要转化成构建器模式的形式,只需要一个注解。
十分钟空间
2022/08/17
9510
二.SpringBoot配置lombok
推荐阅读
相关推荐
还在new对象吗?Builder构建对象了解一下?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验