专栏首页孟君的编程札记Lombok,简化代码的神器,你值得拥有

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

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

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

1、Lombok介绍

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

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官网的描述可以看出:

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依賴包:

<!-- 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

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方法,如下图所示:

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

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方法,如下图高亮部分所示:

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

  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方法,如下图高亮部分所示:

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

3.5 @Data

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

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注解的类如下:

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

反编译查看一下,

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。

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, 反编译后,

  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类,可以采用构建者模式完成赋值,如:

@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方法, 如下图高亮部分所示:

反编译后,其效果如下:

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创建对象示例如下:

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

3.8 @Singular

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

@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的赋值,增加一个方法

   public BookBuilder author(String author)
    {
      if (authors == null)
        authors = new ArrayList();
      authors.add(author);
      return this;
    }

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

Book book = Book.builder().name("Eric").isbn("1234567890asdfghjkl")
                          .author("Eirc")
                          .author("Joan")
                          .build();

3.9 @CleanUp

使用@CleanUp可以完成自动资源管理,如添加close()方法关闭资源。
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);
    }
  }
}

等价于

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

 For non-static methods, a field named {@code $lock} is used, 
 and for static methods, {@code $LOCK} is used. 

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

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。

反编译查看代码,

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的实现,所以代码也就等价于:

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进行日志记录。

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

}

其等价于:

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日志记录,可以说非常方便。

Hello,mengjun
10:49:33.765 [main] INFO com.wangmengjun.tutorial.lombok.LogExample - Method greeting, name is mengjun

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

 <!-- 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

创建

private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@JBossLog

创建

private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);

@Log

创建

private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j

创建

private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2

创建

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文件
在解析和输入阶段,编译器会解析源文件到一个抽象语法树( 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注解 -- 这个可以本文示例中找到 )。

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中的源代码如下:

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也可以在诸多互联网公司的开源代码中看到,大家可以根据自身的需要进行选择。

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

本文分享自微信公众号 - 孟君的编程札记(gh_0f0f5e0ae1de)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 七夕算法:521. 最长特殊序列 Ⅰ

    https://leetcode-cn.com/problems/longest-uncommon-subsequence-i/

    灵魂画师牧码
  • Spring 常犯的 10 大错误,尤其是最后一个!

    译文 | cnblogs.com/liululee/p/11235999.html

    格姗知识圈
  • 聊聊sharding-jdbc的ShardingTracer

    incubator-shardingsphere-4.0.0-RC1/sharding-opentracing/src/main/java/org/apache...

    codecraft
  • Kali Linux渗透基础知识整理(二) 漏洞扫描 二(附送教程)

    这次继续上一篇文章,以后的每一篇文章底部都会推送一下教程或者一些实用工具哦,所以请大家认真看到底!

    网e渗透安全部
  • ​测试开发进阶(二)

    https://pythonguidecn.readthedocs.io/zh/latest/writing/structure.html

    zx钟
  • 浅谈消息队列 2

    JMS的客户端之间可以通过JMS服务进行异步的消息传输。API是一个消息服务的标准或者说是规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。...

    小蜜蜂
  • JVM优化之逃逸分析与分配消除

    在这期文章中,我们将要深入介绍一下逃逸分析(escape analysis)技术,这是JVM最有意思的优化手段之一。逃逸分析是JVM的一项自动分析变量作用域的技...

    哲洛不闹
  • Java的ThreadPoolExecutor

    Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程。在底层,操作系统内核将这些线程映射到...

    用户3467126
  • Go 语言基础入门教程 —— 第一个 Go 程序

    使用 Go 语言之前,首先要安装 Go。Go 为 Linux、Mac、Windows 等不同的平台分别提供了相应的安装包:https://golang.goog...

    学院君
  • 聊聊sharding-jdbc的ShardingMasterSlaveRouter

    本文主要研究一下sharding-jdbc的ShardingMasterSlaveRouter

    codecraft

扫码关注云+社区

领取腾讯云代金券