Lombok的使用与原理

不念不忘少年蓝@ 2022-05-22 12:07 294阅读 0赞

一、Lombok的简介

Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的Java模型对象(POJO)。

在开发环境中使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。

对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。

在IDEA中安装Lombok的插件

想要体验一把Lombok的话,得先在自己的开发环境中安装上对应的插件。下面先为大家展示下如何在IDEA中安装上Lombok插件。

(1)通过IntelliJ的插件中心寻找Lombok

2018062323491754

(2)从Intellij插件中心安装Lombok

20180623234941583

另外需要注意的是,在使用lombok注解的时候记得要导入lombok.jar包到工程,如果使用的是Maven的工程项目的话,要在其pom.xml中添加依赖如下:

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <version>1.18.0</version>
  5. <scope>provided</scope>
  6. </dependency>

好了,就这么几步后就可以在Java工程中开始用Lombok这款开发神器了。下文将会给大家介绍Lombok中一些注解的使用方法,让大家对如何用这些注解有一个大致的了解。

二、Lombok注解使用方法

Lombok常用注解介绍

下面先来看下Lombok中主要几个常用注解介绍:

20180623235114205

Lombok的基本使用示例

(1)Val可以将变量申明是final类型。

  1. public static void main(String[] args) {
  2. val setVar = new HashSet<String>();
  3. val listsVar = new ArrayList<String>();
  4. val mapVar = new HashMap<String, String>();
  5. //=>上面代码相当于如下:
  6. final Set<String> setVar2 = new HashSet<>();
  7. final List<String> listsVar2 = new ArrayList<>();
  8. final Map<String, String> maps2 = new HashMap<>();
  9. }

(2)@NonNull注解能够为方法或构造函数的参数提供非空检查。

  1. public void notNullExample(@NonNull String string) {
  2. //方法内的代码
  3. }
  4. //=>上面代码相当于如下:
  5. public void notNullExample(String string) {
  6. if (string != null) {
  7. //方法内的代码相当于如下:
  8. } else {
  9. throw new NullPointerException("null");
  10. }
  11. }

(3)@Cleanup注解能够自动释放资源。

  1. public void jedisExample(String[] args) {
  2. try {
  3. @Cleanup Jedis jedis = redisService.getJedis();
  4. } catch (Exception ex) {
  5. logger.error(“Jedis异常:”,ex)
  6. }
  7. //=>上面代码相当于如下:
  8. Jedis jedis= null;
  9. try {
  10. jedis = redisService.getJedis();
  11. } catch (Exception e) {
  12. logger.error(“Jedis异常:”,ex)
  13. } finally {
  14. if (jedis != null) {
  15. try {
  16. jedis.close();
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. }
  22. }

(4)@Getter/@Setter注解可以针对类的属性字段自动生成Get/Set方法。

  1. public class OrderCreateDemoReq{
  2. @Getter
  3. @Setter
  4. private String customerId;
  5. @Setter
  6. @Getter
  7. private String poolId;
  8. //其他代码……
  9. }
  10. //上面请求Req类的代码相当于如下:
  11. public class OrderCreateDemoReq{
  12. private String customerId;
  13. private String poolId;
  14. public String getCustomerId(){
  15. return customerId;
  16. }
  17. public String getPoolId(){
  18. return poolId;
  19. }
  20. public void setCustomerId(String customerId){
  21. this.customerId = customerId;
  22. }
  23. public void setPoolId(String poolId){
  24. this.pool = pool;
  25. }
  26. }

(5)@ToString注解,为使用该注解的类生成一个toString方法,默认的toString格式为:ClassName(fieldName= fieleValue ,fieldName1=fieleValue)。

  1. @ToString(callSuper=true,exclude="someExcludedField")
  2. public class Demo extends Bar {
  3. private boolean someBoolean = true;
  4. private String someStringField;
  5. private float someExcludedField;
  6. }
  7. //上面代码相当于如下:
  8. public class Demo extends Bar {
  9. private boolean someBoolean = true;
  10. private String someStringField;
  11. private float someExcludedField;
  12. @Override
  13. public String toString() {
  14. return "Foo(super=" + super.toString() +
  15. ", someBoolean=" + someBoolean +
  16. ", someStringField=" + someStringField + ")";
  17. }
  18. }

(6)@EqualsAndHashCode注解,为使用该注解的类自动生成equalshashCode方法。

  1. @EqualsAndHashCode(exclude = {
  2. "id"}, callSuper =true)
  3. public class LombokDemo extends Demo{
  4. private int id;
  5. private String name;
  6. private String gender;
  7. }
  8. //上面代码相当于如下:
  9. public class LombokDemo extends Demo{
  10. private int id;
  11. private String name;
  12. private String gender;
  13. @Override
  14. public boolean equals(final Object o) {
  15. if (o == this) return true;
  16. if (o == null) return false;
  17. if (o.getClass() != this.getClass()) return false;
  18. if (!super.equals(o)) return false;
  19. final LombokDemo other = (LombokDemo)o;
  20. if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
  21. if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
  22. return true;
  23. }
  24. @Override
  25. public int hashCode() {
  26. final int PRIME = 31;
  27. int result = 1;
  28. result = result * PRIME + super.hashCode();
  29. result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
  30. result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
  31. return result;
  32. }
  33. }

(7) @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor,这几个注解分别为类自动生成了无参构造器、指定参数的构造器和包含所有参数的构造器。

  1. @RequiredArgsConstructor(staticName = "of")
  2. @AllArgsConstructor(access = AccessLevel.PROTECTED)
  3. public class ConstructorExample<T> {
  4. private int x, y;
  5. @NonNull private T description;
  6. @NoArgsConstructor
  7. public static class NoArgsExample {
  8. @NonNull private String field;
  9. }
  10. }
  11. //上面代码相当于如下:
  12. @RequiredArgsConstructor(staticName = "of")
  13. @AllArgsConstructor(access = AccessLevel.PROTECTED)
  14. public class ConstructorExample<T> {
  15. private int x, y;
  16. @NonNull private T description;
  17. @NoArgsConstructor
  18. public static class NoArgsExample {
  19. @NonNull private String field;
  20. }
  21. }
  22. public class ConstructorExample<T> {
  23. private int x, y;
  24. @NonNull private T description;
  25. private ConstructorExample(T description) {
  26. if (description == null) throw new NullPointerException("description");
  27. this.description = description;
  28. }
  29. public static <T> ConstructorExample<T> of(T description) {
  30. return new ConstructorExample<T>(description);
  31. }
  32. @java.beans.ConstructorProperties({
  33. "x", "y", "description"})
  34. protected ConstructorExample(int x, int y, T description) {
  35. if (description == null) throw new NullPointerException("description");
  36. this.x = x;
  37. this.y = y;
  38. this.description = description;
  39. }
  40. public static class NoArgsExample {
  41. @NonNull private String field;
  42. public NoArgsExample() {
  43. }
  44. }
  45. }

(8)@Data注解作用比较全,其包含注解的集合@ToString,@EqualsAndHashCode,所有字段的@Getter和所有非final字段的@Setter, @RequiredArgsConstructor。其示例代码可以参考上面几个注解的组合。

(9)@Builder注解提供了一种比较推崇的构建值对象的方式。

  1. @Builder
  2. public class BuilderExample {
  3. private String name;
  4. private int age;
  5. @Singular private Set<String> occupations;
  6. }
  7. //上面代码相当于如下:
  8. public class BuilderExample {
  9. private String name;
  10. private int age;
  11. private Set<String> occupations;
  12. BuilderExample(String name, int age, Set<String> occupations) {
  13. this.name = name;
  14. this.age = age;
  15. this.occupations = occupations;
  16. }
  17. public static BuilderExampleBuilder builder() {
  18. return new BuilderExampleBuilder();
  19. }
  20. public static class BuilderExampleBuilder {
  21. private String name;
  22. private int age;
  23. private java.util.ArrayList<String> occupations;
  24. BuilderExampleBuilder() {
  25. }
  26. public BuilderExampleBuilder name(String name) {
  27. this.name = name;
  28. return this;
  29. }
  30. public BuilderExampleBuilder age(int age) {
  31. this.age = age;
  32. return this;
  33. }
  34. public BuilderExampleBuilder occupation(String occupation) {
  35. if (this.occupations == null) {
  36. this.occupations = new java.util.ArrayList<String>();
  37. }
  38. this.occupations.add(occupation);
  39. return this;
  40. }
  41. public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
  42. if (this.occupations == null) {
  43. this.occupations = new java.util.ArrayList<String>();
  44. }
  45. this.occupations.addAll(occupations);
  46. return this;
  47. }
  48. public BuilderExampleBuilder clearOccupations() {
  49. if (this.occupations != null) {
  50. this.occupations.clear();
  51. }
  52. return this;
  53. }
  54. public BuilderExample build() {
  55. Set<String> occupations = new HashSet<>();
  56. return new BuilderExample(name, age, occupations);
  57. }
  58. @verride
  59. public String toString() {
  60. return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
  61. }
  62. }
  63. }

(10)@Synchronized注解类似Java中的Synchronized 关键字,但是可以隐藏同步锁。

  1. public class SynchronizedExample {
  2. private final Object readLock = new Object();
  3. @Synchronized
  4. public static void hello() {
  5. System.out.println("world");
  6. }
  7. @Synchronized("readLock")
  8. public void foo() {
  9. System.out.println("bar");
  10. }
  11. //上面代码相当于如下:
  12. public class SynchronizedExample {
  13. private static final Object $LOCK = new Object[0];
  14. private final Object readLock = new Object();
  15. public static void hello() {
  16. synchronized($LOCK) {
  17. System.out.println("world");
  18. }
  19. }
  20. public void foo() {
  21. synchronized(readLock) {
  22. System.out.println("bar");
  23. }
  24. }
  25. }

四、Lombok背后的自定义注解原理

可能熟悉Java自定义注解的同学已经猜到,Lombok这款插件正是依靠可插件化的Java自定义注解处理API(JSR 269: Pluggable Annotation Processing API)来实现在Javac编译阶段利用“Annotation Processor”对自定义的注解进行预处理后生成真正在JVM上面执行的“Class文件”。有兴趣的同学反编译带有Lombok注解的类文件也就一目了然了。其大致执行原理图如下:

20180623235416945

从上面的这个原理图上可以看出Annotation Processing是编译器在解析Java源代码和生成Class文件之间的一个步骤。其中Lombok插件具体的执行流程如下:

20180623235425529

从上面的Lombok执行的流程图中可以看出,在Javac 解析成AST抽象语法树之后, Lombok 根据自己编写的注解处理器,动态地修改 AST,增加新的节点(即Lombok自定义注解所需要生成的代码),最终通过分析生成JVM可执行的字节码Class文件。使用Annotation Processing自定义注解是在编译阶段进行修改,而JDK的反射技术是在运行时动态修改,两者相比,反射虽然更加灵活一些但是带来的性能损耗更加大。

发表评论

表情:
评论列表 (有 0 条评论,294人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java开发神器Lombok使用原理

    在面向对象编程中必不可少需要在代码中定义对象模型,而在基于Java的业务平台开发实践中尤其如此。相信大家在平时开发中也深有感触,本来是没有多少代码开发量的,但是因为定义的业务模

    相关 lombok原理

            工作了一年多了,在工作中使用Lombok节省了很多代码量,同时简化优化了代码结构,今天讲解一下lombok的原理。         1)在java中,注解的两

    相关 Lombok工作原理使用

    Lombok工作原理 在Lombok使用的过程中,只需要添加相应的注解,无需再为此写任何代码。自动生成的代码到底是如何产生的呢? 核心之处就是对于注解的解析上。JDK5