使用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常用注解.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注解处理器