使用lombok提升代码开发效率

一、lombok介绍

lombok是一款为了简化代码而生的工具。按照java传统开发方式,我们每定义一个POJO,都要生成Getter,Setter方法,时不时的还要覆盖一下toString、hashCode;还要提供各式各样的构造函数来满足客户端的调用。看起来都是一些重复的劳动,按照积少成多的规律,项目庞大了以后这些不起眼的动作会占用我们不少的开发时间。so,lombok就是为此而生! 而且现在越来越多的第三方开源框架都使用了lombok,如果checkout下来源码就会发现各种报错,如果不知道有个lombok的东西存在,心里可能还会有点不爽”xxx,竟然连个getter,setter都不提供一下!我怎么扩展?”。好吧,开始进入正题。

二、开始lombok之旅
2.1 安装
  • idea上安装lombok插件(setting->plugin->repository->搜索lombok->安装后重启)
    如果因为网络问题不能在线安装,可以访问https://plugins.jetbrains.com/idea下载下来,通过install from disk离线安装。(注意:lombok版本和idea版本一定要对应上,如果是idea 2018.2,则需要下载lombok 2018.2的版本,不然就会提示版本不兼容),如果能在线安装应该不会有这个问题.
  • pom文件增加依赖
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.16.18</version>
  <scope>provided</scope>
</dependency>
2.2 先开始一个例子

定义一个Person对象:

public class Person {
    @Getter
    @Setter
    private Integer id;

    @Getter
    @Setter
    private String userName;
}

我不给它新增Getter,Setter方法,只是在它的成员属性上加上了lombok提供的两个注解,然后编译一下.就可以像原来那种有get/set的方式来使用了。美滋滋~

    Person person = new Person();
    person.setUserName("jerrik");

我们来看一下它反编译后的字节码:

  public getId()Ljava/lang/Integer;
   L0
    LINENUMBER 15 L0
    ALOAD 0
    GETFIELD com/tenpay/fit/Person.id : Ljava/lang/Integer;
    ARETURN
    ...

  // access flags 0x1
  public setId(Ljava/lang/Integer;)V
   L0
    LINENUMBER 16 L0
    ALOAD 0
    ALOAD 1
    PUTFIELD com/tenpay/fit/Person.id : Ljava/lang/Integer;
    RETURN
     ...

  // access flags 0x1
  public getUserName()Ljava/lang/String;
   L0
    LINENUMBER 19 L0
    ALOAD 0
    GETFIELD com/tenpay/fit/Person.userName : Ljava/lang/String;
    ARETURN
    ...

  // access flags 0x1
  public setUserName(Ljava/lang/String;)V
   L0
    LINENUMBER 20 L0
    ALOAD 0
    ALOAD 1
    PUTFIELD com/tenpay/fit/Person.userName : Ljava/lang/String;
    RETURN
    ...
}

是不是瞬间秒懂了?。其实lombok就是编译时给我们增强了,我们只是加了@Getter和@Setter,就给我们生成了get/set方法。依次类推,肯定还会有其它注解,帮我们做了各种各样的事情。下面一起来看看.

三、lombok常用注解罗列

《使用lombok提升代码开发效率》 lombok常用注解.png

这图是网上的,还有@Slf4j注解比较常用,不需要每个类都声明个logger,直接用
log.info()就行了。

四、来个复杂点的例子
@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
@Builder
@ToString
public class Person {
    private Integer id;

    private String userName;

    @Synchronized
    public void syncAwaitPollRecords(@NonNull String fullFileName){
        try {
            @Cleanup  FileInputStream inputStream = new FileInputStream(new File(fullFileName));
        }catch (Exception ex){
            log.error("synn await records error",ex);
        }
    }
}

这里的@Synchronized说明该方法是同步方法,@Cleanup说明使用完后会自动生成关闭流的方法。出错时直接使用log.error即可,不用定义logger.
客户端调用说明:

    //第一种(@NoArgsConstructor)
    Person person = new Person();
    person.setUserName("jerrik");
    person.setId(3);

    //第二种(@AllArgsConstructor)
    Person person2 = new Person(123,"jerrik");

    //第三种(@Builder注解)
    Person person3 = new 
    Person.PersonBuilder().id(3).userName("jerrik").build();

整个字节码展示:

// class version 52.0 (52)
// access flags 0x21
public class com/tenpay/fit/Person {

  // compiled from: Person.java
  // access flags 0x9
  public static INNERCLASS com/tenpay/fit/Person$PersonBuilder com/tenpay/fit/Person PersonBuilder

  // access flags 0x1A
  private final static Lorg/slf4j/Logger; log

  // access flags 0x12
  private final Ljava/lang/Object; $lock

  // access flags 0x2
  private Ljava/lang/Integer; id

  // access flags 0x2
  private Ljava/lang/String; userName

  // access flags 0x1
  public syncAwaitPollRecords(Ljava/lang/String;)V
    #判断参数是否为空
    @Llombok/NonNull;() // invisible, parameter 0
    TRYCATCHBLOCK L0 L1 L2 java/lang/Exception
    TRYCATCHBLOCK L3 L4 L5 null
    TRYCATCHBLOCK L5 L6 L5 null

    #加锁
    GETFIELD com/tenpay/fit/Person.$lock : Ljava/lang/Object;
    NEW java/lang/NullPointerException
    DUP
    LDC "fullFileName"
    INVOKESPECIAL java/lang/NullPointerException.<init> (Ljava/lang/String;)V
    ATHROW
   L0
    LINENUMBER 31 L0
   FRAME APPEND [java/lang/Object]
    NEW java/io/FileInputStream
    DUP
    NEW java/io/File
    DUP
    ALOAD 1
    INVOKESPECIAL java/io/File.<init> (Ljava/lang/String;)V
    INVOKESPECIAL java/io/FileInputStream.<init> (Ljava/io/File;)V
    ASTORE 3
   L8
    ALOAD 3
    INVOKESTATIC java/util/Collections.singletonList (Ljava/lang/Object;)Ljava/util/List;
    ICONST_0
    INVOKEINTERFACE java/util/List.get (I)Ljava/lang/Object;
    IFNULL L1
    ALOAD 3

    #关流
    INVOKEVIRTUAL java/io/FileInputStream.close ()V

    LINENUMBER 33 L10
    GETSTATIC com/tenpay/fit/Person.log : Lorg/slf4j/Logger;
    LDC "synn await records error"
    ALOAD 3

    #加日志
    INVOKEINTERFACE org/slf4j/Logger.error (Ljava/lang/String;Ljava/lang/Throwable;)V

  // access flags 0x9
  public static builder()Lcom/tenpay/fit/Person$PersonBuilder;
   L0
    LINENUMBER 21 L0
    #建造者模式
    NEW com/tenpay/fit/Person$PersonBuilder

  // access flags 0x1
  public getId()Ljava/lang/Integer;
   L0
    LINENUMBER 24 L0
    ALOAD 0
    GETFIELD com/tenpay/fit/Person.id : Ljava/lang/Integer;
    ARETURN

  // access flags 0x1
  public getUserName()Ljava/lang/String;
   L0
    LINENUMBER 26 L0
    ALOAD 0
    GETFIELD com/tenpay/fit/Person.userName : Ljava/lang/String;
    ARETURN

  // access flags 0x1
  public setId(Ljava/lang/Integer;)V
   L0
    LINENUMBER 17 L0
    ALOAD 0
    ALOAD 1
    PUTFIELD com/tenpay/fit/Person.id : Ljava/lang/Integer;
    RETURN

  // access flags 0x1
  public setUserName(Ljava/lang/String;)V
   L0
    LINENUMBER 17 L0
    ALOAD 0
    ALOAD 1
    PUTFIELD com/tenpay/fit/Person.userName : Ljava/lang/String;
    RETURN

  // access flags 0x1
  public equals(Ljava/lang/Object;)Z
   L0
    LINENUMBER 17 L0
    ALOAD 1
    ALOAD 0
    IF_ACMPNE L1
    ICONST_1
    IRETURN
   L3
    ALOAD 2
    ALOAD 0
    INVOKEVIRTUAL com/tenpay/fit/Person.canEqual (Ljava/lang/Object;)Z
    IFNE L4
    ICONST_0
    IRETURN


  // access flags 0x4
  protected canEqual(Ljava/lang/Object;)Z
   L0
    LINENUMBER 17 L0
    ALOAD 1
    INSTANCEOF com/tenpay/fit/Person
    IRETURN

  // access flags 0x1
  public hashCode()I
   L0
    LINENUMBER 17 L0
    BIPUSH 59
    ISTORE 1
   L1
    ICONST_1
    ISTORE 2
   L2
    ALOAD 0
    INVOKEVIRTUAL com/tenpay/fit/Person.getId ()Ljava/lang/Integer;
    ASTORE 3

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 18 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L1

  // access flags 0x1
  public <init>(Ljava/lang/Integer;Ljava/lang/String;)V
  @Ljava/beans/ConstructorProperties;(value={"id", "userName"})
   L0
    LINENUMBER 19 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V

  // access flags 0x1
  public toString()Ljava/lang/String;
   L0
    LDC "Person(id="
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 0
    INVOKEVIRTUAL com/tenpay/fit/Person.getId ()Ljava/lang/Integer;
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;
    LDC ", userName="
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

  // access flags 0x8
  static <clinit>()V
   L0
    LINENUMBER 20 L0
    LDC Lcom/tenpay/fit/Person;.class
}
五、总结一下

lombok是编译时增强的工具,idea lombok插件只是为了告诉开发者增强了某些方法,如果不安装idea插件,如果要手动set,get的时候就会报错.如果你能忍受,其实也是可以的,至少不会影响程序的最终结果。这点有点像微服务中的SPI接口,如果没有钩子程序,没法知道具体的方法名和参数。
而且oracle jdk也是支持lombok的,不用担心程序的打包问题,所以放心大胆的使用lombok吧!
推荐阅读:
java注解处理器

    原文作者:jerrik
    原文地址: https://www.jianshu.com/p/629909a61a26
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞