Lombok 开发效率插件深入剖析

一、Lombok 是什么
  • 官方介绍

    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.

  • 中文翻译

    Project Lombok 是一个 Java 库,它可以自动插入你的编辑器和构建工具中,为你的 Java 添彩。
    再也不用写另一个 getterequals 方法了,只需一个注释,你的类就有了一个功能齐全的构建器,自动记录变量,还有更多。

  • 白话解释

    Lombok 是一种 Java 实用工具,可以用来帮助开发人员消除 Java 中冗长的固定代码(get、set、toString、hashCode、equals… …),尤其是对 Java 对象(POJO),它通过注解来实现这一目的

  • Lombok 原理

    • JSR 269(点我了解详情) 插件化注解处理 APIPluggable Annotation Processing API

    • JSR 269 最大的特点是注解可以在编译期间处理逻辑和修改代码,即:@Retention(RetentionPloicy.SOURCE) 修饰的注解

    • Lombol 编译逻辑处理过程
      Mark

  • JSR 269 原理

    1. 需要使用 JSR 269 规范的自定义插件都需要采用 JAVASPI 机制来实现服务的发现

    2. 自定义注解处理的业务逻辑类都需要继承 AbstractProcessor 类,AbstractProcessor 实现了 Processor 接口

    3. 实现自定义 JSR 269 规范的编译期间注解方式

      @SupportedAnnotationTypes(value = {"com.xxx.xxx.注解定义接口"})
      @SupportedSourceVersion(value = SourceVersion.RELEASE_8)
      public class MyProcesssor extends AbstractProcessor {
          @Override
          public boolean process(Set<? extends TypeElement> annotations, .....) {
              // 具体注解业务逻辑处理位置
              ... ...
          }
      }
      
      project
          - resource
              - META-INFO.services
                  # 这是一个文件(Spring boot starter 中都 spring.factory 类似)
                  - javax.annotation.processing.Processor
                      # 这是文件中的内容(实际内容顶格且没有 -- com.xxx.xxx.MyProcessor
      
    4. 更多具体细节可以参考 Lombok 的源码实现
      Mark

二、Lombok 为什么
  1. 每次定义 JavaBean 的时候,都需要手动生成 get() set() 等固定的模版方法,没有技术含量的同时降低了工作效率

  2. 每次修改 JavaBean 的时候,都需要手动修改 get() set() 等固定的模版方法,没有技术含量的同时降低了工作效率

  3. 属性判空操作 @NonNull 可以方便快速的进行业务字段校验(当然 Validation 框架也是一个很好的选择)

三、Lombok 怎么用
  1. Lombok 安装

    • IDEA 中安装 Lombok 插件(新版本的 IntelliJ IDEA 已经集成了 Lombok) 插件,无需再安装(再一次说明了 Lombok 的普及性)

      # 安装步骤
      IDEA -> File -> Settings -> Plugins -> MarketPlace -> Lombok 安装后重启 IDEA  
      
    • 项目中引入 Lombok 的依赖

      <dependency>
      	<groupId>org.projectlombok</groupId>
      	<artifactId>lombok</artifactId>
      	<!-- 可以采用最新版本 -->
      	<version>1.18.22</version>
      	<!-- provided 编译阶-->
      	<scope>provided</scope>
      </dependency>
      
    • IDEA 开启自动注解处理功能

      # 设置步骤
      IDEA -> FIle -> Build,Execution,Deployment -> Annotation Processors -> Enable annotation processing(勾选)(JRS 269 的功能都需要勾选)
      
  2. 常用注解之 —— @Getter@Setter

    • 作用范围:
      字段

    • 功能说明:
      添加到字段上 -> 该字段自动生成 gettersetter 方法和方法的访问级别
      添加到类上面 -> 该类成员变量自动生成 gettersetter 方法和方法访问级别

    • 使用效果:
      Mark
      Mark
      Mark

      P.S

      如果成员变量只被 final 修饰,那么会自动生成该变量的 getter 方法,不会生成 setter 方法

  3. 常用注解之 —— ToString

    • 作用范围:

    • 功能说明:
      重写 toString() 方法来覆盖 Object 对象中的 toString() ,默认重写的方法是该类中所有的成员变量 K - V 组合字符串(其中 static 修饰的不会被输出)

    • 使用效果:

      @ToString
      public class User implements Serializable {
      
          private static final long serialVersionUID = 4229562213733224501L;
      
          private static String flagStatic = "";
          private final String flagFinal = "123";
          private long id;
          private String name;
          private float age;
          private boolean gender;
          @Getter(value = AccessLevel.NONE)
          @Setter(value = AccessLevel.NONE)
          private String password;
          private String telephone;
          private String email;
      }
      
      // 反编译后的 toString(),其中 static 修饰的不会被输出
      public String toString() {
          return "User(flagFinal=" + this.getFlagFinal() + ", id=" + this.getId() + ", name=" + this.getName() + ", age=" + this.getAge() + ", gender=" + this.isGender() + ", password=" + this.password + ", telephone=" + this.getTelephone() + ", email=" + this.getEmail() + ")";
      }
      

      P.S

      // exclude 和 of 是互斥的,不能同时使用
      @ToString(exclude = {"排除输出字段1,排除输出字段2,..."}, of = {"仅输出字段1,仅输出字段2,..."})
      
      @ToString(of = {"name", "gender"})
      public class User implements Serializable {
      
          private static final long serialVersionUID = 4229562213733224501L;
      
          private static String flagStatic = "";
          private final String flagFinal = "123";
          private long id;
          private String name;
          private float age;
          private boolean gender;
          @Getter(value = AccessLevel.NONE)
          @Setter(value = AccessLevel.NONE)
          private String password;
          private String telephone;
          private String email;
      }
      
      // 反编译后的 toString(),其中之后 of 包含的字段会被输出
      public String toString() {
          return "User(name=" + this.name + ", gender=" + this.gender + ")";
      }
      
  4. 常用注解之 —— @EqualsAndHashCode

    • 作用范围:

    • 功能说明:

      • 判断类对象是否相等的方法,可以采用默认的模版判断也可以自定义业务规则来判断,同样可以为 @EqualsAndHashCode 设置 excludeof 属性来包含或者排除某些属性(默认是将类中所有的成员变量都判断一遍,看看是否相等,全部相等才任务两个类相等)
      • EqualsHashCode 需要保持逻辑上的一致
    • 使用效果:
      Mark

  5. 常用注解之 —— @NonNull

    • 作用范围:
      方法/构造器的参数成员变量

    • 功能说明:
      判断该参数不能为 null,如果为 null 则抛出 NullPointerException

    • 使用效果
      Mark
      Mark
      Mark
      Mark

  6. 常用注解之 —— @NoArgsConstructor @RequiredArgsConstructor @AllArgsConstructor

    • 作用范围:

    • 功能说明:

      构造注解注解含义
      @NoArgsConstructor生成类的无参构造函数
      @RequiredArgsConstructor生成类的被 @NonNull 修饰和 final 修饰且没有赋初始值的有参构造函数
      @AllArgsConstructor生成类的全参构造函数
    • 使用效果:
      Mark

    P.S
    以上构造函数注解也可以限定构造函数的修饰符,如:

    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    
  7. 常用注解之 —— @Data

    • 作用范围:

    • 功能说明:
      是注解 @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode 的组合写法

    • 使用效果:
      Mark

  8. 常用注解之 —— @Builder

    • 作用范围:

    • 功能说明:
      流式编程方式
      Mark

    • 使用效果:
      Mark

  9. 常用注解之 —— @Accessors

    • 作用范围:

    • 功能说明:

      • @Accessors 注解是不作任何事情的,它需要 @Data 或者 @Getter@Setter 注解的协调使用
      • 链式编程方式
        注解属性程序效果
        chain = true开启链式编程(默认关闭)
        fluent = true开启更加流利的链式编程(默认关闭)
      • fluent = true Lombok 会将 setter getter 方法的前缀 set get 去掉,直接通过属性名称来点出属性 getter setter
    • 使用效果:
      Mark
      Mark

  10. 常用注解之 —— @Log @Slf4j

    • 作用范围:

    • 功能说明:
      其实就是替代了创建日志对象的固定写法

      @Slf4j
      public class User implements Serializable {
      
          // private static final Logger log = LoggerFactory.getLogger(User.class);
          
          ... ...
      }
      
    • 使用效果:
      Mark

  11. 常用注解之 —— @Cleanup

    • 作用范围:
      所有需要关闭流的变量上

    • 功能说明:
      简化了输入输出流编程中的异常处理和流的关闭问题

    • 使用效果:

      • 传统写法

        @Test
        void generateIOTest() {
            String sourceFile = "/Users/rambo/Desktop/4_4_1636623756947.mp3";
            String targetFile = "/Users/rambo/Desktop/11111111111111111.mp3";
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try {
                // 1、定义文件输入和输出流
                fis = new FileInputStream(sourceFile);
                fos = new FileOutputStream(targetFile);
                // 2、定义临时的文件缓冲区
                byte[] bytes = new byte[10240];
                // 3、从文件输入流拷贝文件到输出流(没有读完继续读,直到读完为止)
                int contentLength = 0;
                while ((contentLength = fis.read(bytes)) != -1) {
                    // 4、将读到临时文件缓冲区的内容写入到输出流
                    fos.write(bytes, 0, contentLength);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                // 5、关闭流
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
      • JDK 8 的优雅写法

        @Test
        void newerIOTest() {
            String sourceFile = "/Users/rambo/Desktop/4_4_1636623756947.mp3";
            String targetFile = "/Users/rambo/Desktop/22222222222222222.mp3";
        
            try(
                // 1、定义文件输入和输出流
                InputStream is = new FileInputStream(sourceFile);
                OutputStream os = new FileOutputStream(targetFile)) {
                // 2、定义临时的文件缓冲区
                byte[] bytes = new byte[10240];
                // 3、从文件输入流拷贝文件到输出流(没有读完继续读,直到读完为止)
                int contentLength = 0;
                while ((contentLength = is.read(bytes)) != -1) {
                    // 4、将读到临时文件缓冲区的内容写入到输出流
                    os.write(bytes, 0, contentLength);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
      • Lombok 写法

        @Test
        void lombokIOTest() throws IOException {
            String sourceFile = "/Users/rambo/Desktop/4_4_1636623756947.mp3";
            String targetFile = "/Users/rambo/Desktop/11111111111111111.mp3";
            // 1、定义文件输入和输出流
            @Cleanup 
            InputStream fis = new FileInputStream(sourceFile);
            @Cleanup
            OutputStream fos = new FileOutputStream(targetFile);
            // 2、定义临时的文件缓冲区
            byte[] bytes = new byte[10240];
            // 3、从文件输入流拷贝文件到输出流(没有读完继续读,直到读完为止)
            int contentLength = 0;
            while ((contentLength = fis.read(bytes)) != -1) {
                // 4、将读到临时文件缓冲区的内容写入到输出流
                fos.write(bytes, 0, contentLength);
            }
        }
        

      Mark
      Mark

P.S
Lombok 采用 JSR 269 特性通过注解来修改 AST 语法树生成的固定模版方法时,如果对某个指定模版进行来手动编码,那么手动编码的优先级高于 Lombok 生成的模版编码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值