zoukankan      html  css  js  c++  java
  • lombok基本使用

    lombok基本使用


    Lombok实现原理:

    自从Java 6起,javac就支持“JSR 269 Pluggable Annotation Processing API”规范,只要程序实现了该API,就能在javac运行的时候得到调用。

    Lombok就是一个实现了"JSR 269 API"的程序。在使用javac的过程中,它产生作用的具体流程如下:


    1. javac对源代码进行分析,生成一棵抽象语法树(AST)

    2. javac编译过程中调用实现了JSR 269的Lombok程序

    3. 此时Lombok就对第一步骤得到的AST进行处理,找到Lombok注解所在类对应的语法树 (AST),然后修改该语法树(AST),增加Lombok注解定义的相应树节点

    4. javac使用修改后的抽象语法树(AST)生成字节码文件

      @Getter and @Setter
      @FieldNameConstants
      @ToString
      @EqualsAndHashCode
      @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
      @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger
      @Data
      @Builder
      @Singular
      @Delegate
      @Value
      @Accessors
      @Wither
      @SneakyThrows
      

    Lombok注解的使用

    在 IDE 安装了 Lombok 插件后,我们就可以在 pom.xml 文件中添加 Lombok 的依赖进行使用了。

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>
    

    注意:pom 依赖设置 scope 为 provided,是为了让 Lombok 库不被打包进程序。

    @Getter/@Setter

    通常我们编写实体类无论多少个字段,都要为其提供 gettersetter 方法,

    我们常会遇到这种情况:某个实体类新增和修改某个字段,我们都需要单独处理调整,十分麻烦并且重复。这时候如果我们使用 Lombok 提供 @Getter/@Setter 注解就能帮我们省去 getter 和 setter 方法的维护,由 Lombok 对 User 类自动生成 gettersetter 方法,两者最终的字节码时一样的,而我们现在在 User.java 上编写的代码仅仅 7 行即可:

    @Getter
    @Setter
    public class User {
        private Integer id;
        private String username;
        private String password;
    }
    

    然后用测试类 UserTests.java 测试结果如下:

    public class UserTests {
        @Test
        public void test() {
            User user = new User();
            user.setUsername("one");
            user.setPassword("zxc123");
            Assert.assertEquals(user.getUsername(), "one");
            Assert.assertEquals(user.getPassword(), "zxc123");
        }
    }
    

    @Getter/@Setter 注解不仅可以使用在类上,还可以使用在字段上,这样就是表示针对该字段自动生成 getter /setter 方法。

    @Getter
    @Setter
    private String password;
    

    这里该注解使用在类上,还是在字段上的区别就是,如果注解使用在类上,只针对这个类的非静态字段有效。

    需要注意的一点是:如果 @Getter 注解修饰了 boolean 类型的变量,其生成的 getter 方法签名是 isXXX 形式,而不是 getXXX形式。

    除此之外,@Getter/@Setter 还提供访问权限控制的属性 lombok.AccessLevel value(), 默认为 PUBLIC,而其他选值都是枚举类型:MODULE, PROTECTED, PACKAGE, PRIVATE

    2.3 @NonNull

    顾名思义,@NonNull 用于标记类中不能允许为 null 的字段或者参数上,任何使用该字段的地方都生成空指针判断代码,若@NonNull 标记的变量为 null,抛出 NullPointException (NPE) 异常。比如下面示例代码:

    public class User {
        private Integer id;
        private String username;
        private String password;
    
        public User(Integer id, @NonNull String username, @NonNull String password) {
            this.id = id;
            this.username = username;
            this.password = password;
        }
    }
    

    使用了 @NonNull 注解之后我们可以获取到反编译之后的字节码信息如下,这就是 Lombok 给我们生成的最终的代码:

    public class User {
        private Integer id;
        private String username;
        private String password;
    
        public User(Integer id, @NonNull String username, @NonNull String password) {
            if (username == null) {
                throw new NullPointerException("username is marked non-null but is null");
            } else if (password == null) {
                throw new NullPointerException("password is marked non-null but is null");
            } else {
                this.id = id;
                this.username = username;
                this.password = password;
            }
        }
    }
    

    2.4 构造器注解

    再来看下平时经常会遇见的场景,为实体类编写构造器方法,Lombok 提供了三个不同构造器注解 @NoArgsConstructor / @AllArgsConstructor / @RequiredArgsConstructor 分别对用不同构造器方法处理方式,接下来就一一描述。

    • @NoArgsConstructor 为实体类生成无参的构造器方法

    • @AllArgsConstructor 为实体类生成除了static修饰的字段之外带有各参数的构造器方法。

    • @RequiredArgsConstructor 为实体类生成指定字段的构造器方法,而这些字段需要被 final,或者 @NonNull 修饰。

      @RequiredArgsConstructor
        public class User3 {
            private Integer id;
            private final String username;
            @NonNull
            private String password;
        }
      

      编译成功后使用构造器方法时就是这样的效果:User3 user3 = new User3("user3", "zxc123");

      2.5 @ToString

      @ToString 会给类自动生成易阅读的 toString 方法,带上有所非静态字段的属性名称和值,这样就十分便于我们日常开发时进行的打印操作。

      @Getter
      @Setter
      @AllArgsConstructor
      @ToString
      public class User2 {
          private Integer id;
          private String username;
          private String password;
      }
      

      最终编译成字节码,反编译结果如下:

    public class User2 {
        private Integer id;
        private String username;
        private String password;
        // 省去 setter/getter
        public String toString() {
            return "User2(id=" + this.getId() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ")";
        }
    }
    

    另外,注解 @ToString 还支持设置指定哪些字段的日志化输出,哪些不需要出现在 toString 方法中。使用属性 @ToString.Exclude排除不需要在 toString 中出现的字段,使用 @ToString.Include标记需要出现在 toString 中的字段,具体用法可参见示例:

    @Getter
    @Setter
    @AllArgsConstructor
    @ToString
    public class User2 {
        @ToString.Exclude
        private Integer id;
        @ToString.Include
        private String username;
        @ToString.Include
        private String password;
    }
    

    打印 User2 对象的日志效果就是:User2(username=user2, password=zcx123)

    2.6 @EqualsAndHashCode

    @EqualsAndHashCode 注解就是用于根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法,方便我们用于对象间的比较。类似 @ToString@EqualsAndHashCode 还可以使用需要作为比较的字段和排除不需要比较的字段,具体用法可以看如下示例:

    @Getter
    @Setter
    @AllArgsConstructor
    @ToString
    @EqualsAndHashCode
    public class User4 {
        @EqualsAndHashCode.Exclude
        private Integer id;
        @EqualsAndHashCode.Include
        private String username;
        @EqualsAndHashCode.Exclude
        private String password;
    }
    

    写完实体类代码,我们编写测试方法试下效果:

    @Test
    public void testEqual() {
        User4 user4 = new User4(1, "user4", "zxc");
        User4 user4_2 = new User4(1, "user4", "123");
        Assert.assertEquals(user4, user4_2); // ture
    }
    

    2.7 @Data/@Value

    @Data/@Value 注解,提供了更综合的生成代码功能,等价于下面几个注解

    @Getter
    @Setter
    @RequiredArgsConstructor
    @ToString
    @EqualsAndHashCode
    

    两个注解都只能使用在类上,与 @Data 不同, @Value 用来修饰不可变的类上。一般实体类没有特别的限制的话,通常可以直接使用 @Data 注解修饰。

    2.8 @Builder

    @Builder 是一个非常强大的注解,提供了一种基于建造者模式的构建对象的 API。使用 @Builder 注解为给我们的实体类自动生成 builder() 方法,并且直接根据字段名称方法进行字段赋值,最后使用 build()方法构建出一个实体对象。

    @Data
    @Builder
    public class User6 {
        private Integer id;
        private String username;
        private String password;
    }
    
    @Test
    public void testBuilder() {
        User6 user6 = User6.builder().id(1).username("user6").password("zxc123").build();
        log.warn("testLog: {}", user6); // User6(id=1, username=user6, password=zxc123)
    }
    

    需要注意的是 @Builder 不支持父类字段的生成,当一个实体类存在父类时,@Builder 只能生成当前类的字段构建方法。若需要用到父类的字段方法时, Lombok 提供了新的注解 @SuperBuilder 来应对这种情况,下面是 @SuperBuilder 注解的使用方式:

    @SuperBuilder
    @Getter
    @Setter
    public class Parent {
       private int id;
       private String name;
    }
    
    @SuperBuilder
    @Data
    public class Child extends Parent {
        private String childName;
    }
    

    调用示例:

    Child child = Child.builder().id(1).name("父类名称").childName("子类名称").build();
    System.out.println(child.getId());
    

    由于 Lombok Plugin 还未更新支持@SuperBuilder,所以以上写法在 IDEA 下还会提示编译错误,无法找到 builder()方法。

    2.9 日志注解

    正对程序类中常见不同框架 Logger 对象,Lombok 也提供了注解,来自动生成 Logger 对象,实现优雅地输出日志,只需要在类上使用日志注解如 @Log。当然 Lombok 支持了多个日志框架,并且提供对应的注解如下:

    @CommonsLog 等价效果: private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
    
    @Flogger 等价效果: private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
    
    @JBosLog 等价效果: private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
    
    @Log 等价效果: private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
    
    @Log4j 等价效果: private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
    
    @Log4j2 等价效果: private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
    
    @Slf4j 等价效果: private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
    
    @XSlf4j 等价效果: private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
    

    下面代码使用 @Slf4j 注解进行日志输出:

    @Slf4j
    public class UserTests {
        // ....
        @Test
        public void testLog() {
            User5 user5 = new User5();
            user5.setId(1);
            user5.setUsername("user5");
            user5.setPassword("zxc123");
            log.warn("testLog: {}", user5);
       // 21:57:15.488 [main] WARN com.one.learn.lombok.UserTests - testLog: User5(id=1, username=user5, password=zxc123)
        }
    }
    

    2.10 @Cleanup

    @Cleanup 用于标记需要释放清理操作的资源对象变量,如 FileInputStream, FileOutputStream 等,标记之后资源对象使用完毕后,就会被自动关闭和清理,实际上这里 Lombok 实现效果与 Java7 特性 try with resource 一样, 为我们屏蔽了关闭资源的模板代码,下面给出 @Cleanup 的使用示例:

    public class CleanupExample {
        public static void main(String[] args) throws IOException {
            @Cleanup InputStream in = new FileInputStream(args[0]);
            @Cleanup OutputStream out = new FileOutputStream(args[1]);
            byte[] b = new byte[10000];
            while (true) {
                int r = in.read(b);
                if (r == -1) {
                    break;
                }
                out.write(b, 0, r);
            }
        }
    }
    

    装载于:https://www.cnblogs.com/blogtech/p/11994217.html

  • 相关阅读:
    django页面分类和继承
    django前端从数据库获取请求参数
    pycharm配置django工程
    django 应用各个py文件代码
    CF. 1428G2. Lucky Numbers(背包DP 二进制优化 贪心)
    HDU. 6566. The Hanged Man(树形背包DP DFS序 重链剖分)
    小米邀请赛 决赛. B. Rikka with Maximum Segment Sum(分治 决策单调性)
    区间树 学习笔记
    CF GYM. 102861M. Machine Gun(主席树)
    2016-2017 ACM-ICPC East Central North America Regional Contest (ECNA 2016) (B, D, G, H)
  • 原文地址:https://www.cnblogs.com/jinronga/p/12753842.html
Copyright © 2011-2022 走看看