1.Lombok是什么
Lombok是使用java编写的一款开源类库。其主作用的是使用注解来代替一些具有格式固定,没有过多技术含量的编码工作。使我们可以仅仅在代码中添加一个注解(annotation),就可以起到和编写一大段代码一样的作用。对于这些格式固定的的代码,IDE也提供了自动生成的功能,但是无论是自动生产还是手动写的,这些代码在类中是实实在在的存在,有时候,看到一个类文件很长,其中却都是一些,没有任何技术含量的getter和setter方法。无疑会影响我们的代码阅读。使用Lombok可以将这些“无用”的代码,通过相应的注解替换掉。好了,废话少说,进入主题:上面说的“注解”具体是那些注解?这些注解又能代替那些编码工作呢,以及是如何实现的呢?
2.Lombok如何使用
在使用Lombok前,先添加对Lombok的依赖(针对maven)。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
1.@Getter和@Setter
这两个注解对应的就是生产指定字段的getter和setter方法,该注解可以放到类型上也可以放到具体的字段上,放在类型上,表示对类中所有的字段都生成对应的getXXX和setXXX方法,如果加在具体的字段上的话,那么只对具体的字段起作用。
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Setter
使用@Setter和@Getter
@Setter
public class GetterTestWithLombok {
@Getter
private String name;
private int age;
}
不使用Lombok,具有相同功能的代码如下:
public class GetterTestWithLombok {
private String name;
private int age;
public GetterTestWithLombok() {
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return this.name;
}
}
2.@ToString
这个注解只能用在类上,表示生产这个类的toString方法,默认情况下toString返回的字符串中包含所有字段。
使用@ToString
@ToString
public class ToStringTest {
private String name;
}
不使用@ToString,具有相同功能的代码
public class ToStringTest {
private String name;
public ToStringTest() {
}
public String toString() {
return "ToStringTest(name=" + this.name + ")";
}
}
3.@NonNull,被修饰的字段不能赋值NULL。实现原理就是在赋值前,进行非空判断,如果为空抛出NullPointerException异常。
使用@NonNull
public class NonNullExample {
@NonNull
@Setter
private String name;
}
不使用@NonNull,具有相同功能的代码
public class NonNullExample {
@NonNull
private String name;
public NonNullExample() {
}
public void setName(@NonNull String name) {
if(name == null) {
throw new NullPointerException("name");
} else {
this.name = name;
}
}
}
4.@AllArgsConstructor,@RequiredArgsConstructor和@NoArgsConstructor
这三个注解是关于构造函数的,分别对应在日常开发过程中的全参构造,部分参数构造和无参构造。其中比较特殊的是@RequiredArgsConstructor也就是部分参数构造,部分参数,具体是哪部分呢?Lombok没有提供参数让我们配置,而是规定这部分参数为:被final修饰且没有被初始化的字段和被@NonNull修饰的字段。以上注解生成的构造函数中参数的顺序默认和字段定义的顺序是一致的。
以上是比较常用的一些注解,而且这些注解也提供了丰富的参数,方便使用者对生成代码的定制。不过默认的配置已经可以满足大部分的开发需求。当然还有很多其他注解,如@Clean,@Singular等等,这里无法一一展开,具体用法可以参考Lombok文档。
3.Lombok的实现原理
此时有些小伙伴们,要迫不及待的试一下,是否真的如上说的那样好用,开始写测试用例。在写测试用例的过程中,会发现,IDE(这里使用的idea)提示找不到相应的getter/setter方法,其实找不到也是正常的,因为在GetterTestWithLombok类中的确没有定义的gettter/setter方法,有的只是@Getter和@Setter,Idea进行语法检查是完全基于源代码层面的,是无法识别@Getter和@Setter具体是何种含义,idea在代码层面没有找到对应的方法,所以也就提示语法错误。其实这个语法错误也仅仅是在IDE层面的,毕竟IDE没有那么智能,可以不用那么在意,但是对于有代码洁癖,且十分依赖IDE进行语法检查和代码提示的小伙伴来说,就很不爽了,要解决这个问题,可以在IDEA上面增加Lomok的一个插件即可。
添加上插件后,就又可以方便的使用idea的代码语法检查和提示功能了。
接下来开始代码的编译和运行测试,结果发现,源代码无法通过编译。提示找不到符号:
这就要说一下Lombok的工作原理了。在说Lombok的工作原理前,需要先说一点关于java编译器javac的编译过程。
我们都知道java程序在运行前需要经历以下过程:编写java源代码->字节码->机器码->运行。在这个流程中,我们可以参与,并且主动权最大的是在第一步,源代码的编写,也就是定义程序的执行逻辑。在由java源代码->字节码的过程中,主要是javac编译器在工作,javac完成将java源代码转换成符合jvm规范的字节码。在这个转换的过程中,javac主要的做了3个工作:
- 词法语法分析:词法分析将源代码字符流分解成一个个的标记(Token),语法分析将标记序列构造成抽象语法树(AST)。
- 注解处理器处理:注解处理器可以对AST进行一定的更新处理,更新的逻辑具体是什么,取决于注解处理器的实现。
- 语义分析和字节码生成:对抽象语法树进行语义分析,完成语法糖的解析等,最终生成字节码(这个过程不是本文的重点,进行了简化说明)。
自从Java 6开始,javac开始支持JSR 269 Pluggable Annotation Processing API规范,也就是说在满足该规范的前提下,我们可以实现自己的注解处理器,来实现对javac编译器编译过程的人为干预。有了这个,我们就可以在java程序的编译阶段做很多有意思的事情了(有没有觉得注解处理器是观察者模式的一种应用,只不过,我们常用的观察者工作的运行期,注解处理器工作在编译期)。
Lomok的实现原理,就是定义了自己的注解处理器,在java程序编译的阶段对源代码定义的逻辑做了“手脚”,在生成字节码前加上了需要的getter/setter方法,保证生成的字节码也就带有getter/setter方法。大部分的Lombok的注解的Retention都是SOURCE级别的,因为生成字节码后,这些注解的使命就完成了,在字节码层面和运行时不在需要这些注解了。因为jvm关心的是字节码,不关心生成字节码之前的源代码是什么样子(这也是为什么会有那么多可以运行在jvm上的非java语言,只要为这些语言提供一个相应的编译器,将对应的语言编译成满足jvm规范的字节码即可),所以使用Lombok和在源代码里面直接编写getter和setter方法,对于jvm来说是没有差别的,因为javac生成的字节码都是一样的。
之前idea编译不通过,是因为Lombok的注解编译器没有起作用,只要在javac编译java程序时启用Lombok的注解处理器,就可以让程序编译通过了。在idea中设置启用注解编译器即可。
接下来,对程序进行重新编译,进行验证测试。
4.Lombok使用的一些感受
使用lombok的一些感受,使用Lombok可以减少我们日常需要重复编写的部分代码,减少了不少工作量,而且也可以满足大部分的日常开发,但是对于一些比较复杂的代码生成,使用Lombok反而变得更麻烦,使用的过程中,还是需要权衡的。
转载:https://blog.csdn.net/weixin_45701550/article/details/101705251