zoukankan      html  css  js  c++  java
  • Java工具—Lombok

    Lombok的介绍和安装

    参考:

    https://www.cnblogs.com/ooo0/p/12448096.html

    https://www.cnblogs.com/pascall/p/10281169.html

    • 官网:https://projectlombok.org/
    • Lombok介绍:
      • Lombok是一个优秀的Java代码库,简化了Java的编码,为Java代码的精简提供了一种方式
      • 每个JavaBean都会写getter、setter、equals、hashCode、toString等代码,Lombok消除Java的冗长代码,尤其是对于简单的Java对象,只要加上注解就行

    Lombok的使用

    • pom.xml 添加依赖进行版本管理
    <properties>
        <!--锁定 jdk 版本为 1.8-->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        <!--https://mvnrepository.com/artifact/org.projectlombok/lombok/1.18.16-->
        <!--scope=provided,说明它只在编译阶段生效,不需要打入包中, Lombok在编译期将带Lombok注解的Java文件正确编译为完整的Class文件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    
    • 添加IDE工具对Lombok的支持:点击File-- 》Settings界面,安装Lombok插件,然后重启idea

    • IDEA里需要在设置中启用annotation processors,记得重启IDEA!

    Lombok常用注解介绍

    1、@Data:在JavaBean中使用,注解包含包含getter、setter、NoArgsConstructor注解

    2、@Value注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法

    3、@getter和@setter:在JavaBean中使用,注解会生成对应的getter和setter方法

    4、@NoArgsConstructor:在JavaBean中使用,注解会生成对应的无参构造方法

      @AllArgsConstructor:在JavaBean中使用,注解会生成对应的有参构造方法

      @RequiredArgsConstructor :生成private构造方法,使用staticName选项生成指定名称的static方法。

    5、@ToString:在JavaBean中使用,注解会自动重写对应的toStirng方法

      @ToString(exclude={"column1","column2"}):排除多个column列所对应的元素

      @ToString(of={"column1","column2"}):只生成包含多个column列所对应的元素

    6、@EqualsAndHashCode:在JavaBean中使用,注解会自动重写对应的equals方法和hashCode方法

    7、@Slf4j和@Log4j:在需要打印日志的类中使用,项目中使用slf4j和log4j日志框架

    8、@NonNull:注解快速判断是否为空,为空抛出java.lang.NullPointerException

    9、@Accessors(chain = true):链式风格,在调用set方法时,返回这个类的实例对象

    10、@Synchronized:注解自动添加到同步机制,生成的代码并不是直接锁方法,而是锁代码块, 作用范围是方法上

    11、@Cleanup:注解用于确保已分配的资源被释放(IO的连接关闭)

    常用注解—@Setter/@Getter

    注解详解:

    • 作用类上,生成所有成员变量的getter/setter方法
    • 作用于成员变量上,生成该成员变量的getter/setter方法
    • 方法控制访问级别 set和get注解加:@Setter/@Getter(AccessLevel.PROTECTED)
    • 忽略不生成某个字段set/get方法:@Setter/@Getter(AccessLevel.NONE)
    • final成员变量只会生成get
    • static静态成员变量不会生成set/get方法

    新建实体类:User.java

    @Setter
    @Getter
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        public User() {
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Long getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    }
    

    更多属性示例:

    新建实体类:User.java

    @Setter
    @Getter
    public class User {
        private Long id;
    
        /**
         * 不想生成 get方法
         */
        @Getter(AccessLevel.NONE)
        private Integer age;
    
        /**
         * 控制访问权限
         */
        @Getter(AccessLevel.PROTECTED)
        private int salary;
    
        /**
         * final 只会生成get
         */
        private final String name="Sam";
    
        /**
         * 下面两个静态成员变量不会生成set/get方法
         */
        static Date createTime = new Date();
        private static final String address = "广东省广州市";
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private Integer age;
        private int salary;
        private final String name = "Sam";
        static Date createTime = new Date();
        private static final String address = "广东省广州市";
    
        public User() {
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public void setSalary(int salary) {
            this.salary = salary;
        }
    
        public Long getId() {
            return this.id;
        }
    
        public String getName() {
            this.getClass();
            return "Sam";
        }
    
        protected int getSalary() {
            return this.salary;
        }
    }
    

    常用注解—@XxArgsConstructor

    @NoArgsConstructor、@AllArgsConstructor、@RequiredArgsConstructor

    @NoArgsConstructor:生成对应的无参构造方法(一般情况下不会单独使用该注解,因为默认就有无参构造)

    @NoArgsConstructor
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        public User() {
        }
    }
    

    @AllArgsConstructor:生成对应的有参构造方法(全部参数)

    @AllArgsConstructor
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        public User(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    }
    

    注意:一般@AllArgsConstructor和@NoArgsConstructor一起使用,因为使用@AllArgsConstructor后默认就不会生成无参构造了

    @RequiredArgsConstructor:生成一个包含 "特定参数" 的构造器,特定参数指的是:

    • 加上 final 修饰词的变量们
    • 加上@NonNull注解的变量们
    • 注意:不能加上@NoArgsConstructor
    @RequiredArgsConstructor
    public class User {
        @NonNull
        private Long id;
        private final String name;
    }
    

    编译查看字节码:mvn compile

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

    常用注解—@NonNull

    @NonNull:Lombok非空判断、作用于方法上或者属性,用于非空判断,如果为空则抛异常

    @Setter
    @Getter
    public class User {
        @NonNull
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    import lombok.NonNull;
    
    public class User {
        @NonNull
        private Long id;
        private String name;
    
        public User() {
        }
    
        public void setId(@NonNull Long id) {
            if (id == null) {
                throw new NullPointerException("id is marked non-null but is null");
            } else {
                this.id = id;
            }
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @NonNull
        public Long getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    }
    

    常用注解—@ToString

    @ToString:注解会自动重写对应的toStirng方法

    @ToString(exclude={"column1","column2"}):排除多个column列所对应的元素

    @ToString(of={"column1","column2"}):只生成包含多个column列所对应的元素

    @ToString
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        public User() {
        }
    
        public String toString() {
            return "User(id=" + this.id + ", name=" + this.name + ")";
        }
    }
    

    常用注解—@EqualsAndHashCode

    @EqualsAndHashCode:作用于类,覆盖默认的equals和hashCode, 作用于全部属性

    @EqualsAndHashCode(exclude = {"age"}):不包括某个属性

    @EqualsAndHashCode(of = {"name"}):只输出某个属性

    @EqualsAndHashCode
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        public User() {
        }
    
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof User)) {
                return false;
            } else {
                User other = (User)o;
                if (!other.canEqual(this)) {
                    return false;
                } else {
                    Object this$id = this.id;
                    Object other$id = other.id;
                    if (this$id == null) {
                        if (other$id != null) {
                            return false;
                        }
                    } else if (!this$id.equals(other$id)) {
                        return false;
                    }
    
                    Object this$name = this.name;
                    Object other$name = other.name;
                    if (this$name == null) {
                        if (other$name != null) {
                            return false;
                        }
                    } else if (!this$name.equals(other$name)) {
                        return false;
                    }
    
                    return true;
                }
            }
        }
    
        protected boolean canEqual(Object other) {
            return other instanceof User;
        }
    
        public int hashCode() {
            int PRIME = true;
            int result = 1;
            Object $id = this.id;
            int result = result * 59 + ($id == null ? 43 : $id.hashCode());
            Object $name = this.name;
            result = result * 59 + ($name == null ? 43 : $name.hashCode());
            return result;
        }
    }
    

    常用注解—@Data/@Value

    Lombok太多常用的注解一个个加也麻烦,所以出现了两个聚合注解:@Data 和 @Value

    @Data:整合包,只要加了 @Data 这个注解,等于同时加了以下注解

    • @Getter、@Setter
    • @ToString
    • @EqualsAndHashCode
    • @RequiredArgsConstructor

    元注解:

     /** 
     * @see Getter
     * @see Setter
     * @see RequiredArgsConstructor
     * @see ToString
     * @see EqualsAndHashCode
     * @see lombok.Value
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Data {
        String staticConstructor() default "";
    }
    

    使用案例:

    @Data
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        // @RequiredArgsConstructor
        public User() {
        }
    
        // @Getter、@Setter
        public Long getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        // @EqualsAndHashCode
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof User)) {
                return false;
            } else {
                User other = (User)o;
                if (!other.canEqual(this)) {
                    return false;
                } else {
                    Object this$id = this.getId();
                    Object other$id = other.getId();
                    if (this$id == null) {
                        if (other$id != null) {
                            return false;
                        }
                    } else if (!this$id.equals(other$id)) {
                        return false;
                    }
    
                    Object this$name = this.getName();
                    Object other$name = other.getName();
                    if (this$name == null) {
                        if (other$name != null) {
                            return false;
                        }
                    } else if (!this$name.equals(other$name)) {
                        return false;
                    }
    
                    return true;
                }
            }
        }
    
        protected boolean canEqual(Object other) {
            return other instanceof User;
        }
    
        public int hashCode() {
            int PRIME = true;
            int result = 1;
            Object $id = this.getId();
            int result = result * 59 + ($id == null ? 43 : $id.hashCode());
            Object $name = this.getName();
            result = result * 59 + ($name == null ? 43 : $name.hashCode());
            return result;
        }
    
        // @ToString
        public String toString() {
            return "User(id=" + this.getId() + ", name=" + this.getName() + ")";
        }
    }
    

    @Data是使用频率最高的lombok注解,通常@Data 会在一个值可以被更新的对象上,像是日常使用的 DTO 们、或是 JPA 里的 Entity 们,就很适合加上 @Data 注解,也就是:@Data for mutable class

    @Value:也是整合包,但是他会把所有的变量都设成 final 的,其他的就跟 @Data 一样,等于同时加了以下注解:

    • @Getter (注意没有@Setter)
    • @ToString
    • @EqualsAndHashCode
    • @RequiredArgsConstructor

    元注解:

    /**
     * @see lombok.Getter
     * @see lombok.experimental.FieldDefaults
     * @see lombok.AllArgsConstructor
     * @see lombok.ToString
     * @see lombok.EqualsAndHashCode
     * @see lombok.Data
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Value {
       String staticConstructor() default "";
    }
    

    使用案例:

    @Value
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public final class User {
        // 给属性都设置成final
        private final Long id;
        private final String name;
    
        // @RequiredArgsConstructor
        public User(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        // @Getter
        public Long getId() {
            return this.id;
        }
    
        public String getName() {
            return this.name;
        }
    
        // @EqualsAndHashCode
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof User)) {
                return false;
            } else {
                User other = (User)o;
                Object this$id = this.getId();
                Object other$id = other.getId();
                if (this$id == null) {
                    if (other$id != null) {
                        return false;
                    }
                } else if (!this$id.equals(other$id)) {
                    return false;
                }
    
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }
    
                return true;
            }
        }
    
        public int hashCode() {
            int PRIME = true;
            int result = 1;
            Object $id = this.getId();
            int result = result * 59 + ($id == null ? 43 : $id.hashCode());
            Object $name = this.getName();
            result = result * 59 + ($name == null ? 43 : $name.hashCode());
            return result;
        }
    
        // @ToString
        public String toString() {
            return "User(id=" + this.getId() + ", name=" + this.getName() + ")";
        }
    }
    

    上面那个 @Data 适合用在 POJO 或 DTO 上,而这个 @Value 注解,则是适合加在值不希望被改变的类上,像是某个类的值当创建后就不希望被更改,只希望我们读它而已,就适合加上 @Value 注解,也就是 @Value for immutable class

    另外注意一下,此 lombok 的注解 @Value 和另一个 Spring 的注解 @Value 撞名,在 import 时不要 import 错了

    建造模式—@Builder

    @Builder注解:作用在类上,自动生成流式 set 值写法,从此之后再也不用写一堆 setter 了

    @Builder
    public class User {
        private Long id;
        private String name;
    }
    
    // 使用
    User build = User.builder().id(1L).name("Sam").build();
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
    
        User(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public static User.UserBuilder builder() {
            return new User.UserBuilder();
        }
    
        public static class UserBuilder {
            private Long id;
            private String name;
    
            UserBuilder() {
            }
    
            public User.UserBuilder id(Long id) {
                this.id = id;
                return this;
            }
    
            public User.UserBuilder name(String name) {
                this.name = name;
                return this;
            }
    
            public User build() {
                return new User(this.id, this.name);
            }
    
            public String toString() {
                return "User.UserBuilder(id=" + this.id + ", name=" + this.name + ")";
            }
        }
    }
    

    注意:虽然只要加上@Builder注解,我们就能够用流式写法快速设定对象的值,但是 setter 还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对他们取值/赋值

    所以通常是@Data和@Builder 会一起用在同个类上,既方便我们流式写代码,也方便框架做事

    常用注解—@Accessors

    @Accessors:中文含义是存取器,@Accessors用于配置getter和setter方法的生成结果,下面介绍三个属性

    fluent:中文含义是流畅的,设置为true,则getter和setter方法的方法名都是基础属性名,且setter方法返回当前对象

    @Data
    @Accessors(fluent = true)
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
        
        // 生成的getter和setter方法如下,方法体和其他方法略
        public Long id() {}
        public User id(Long id) {}
        public String name() {}
        public User name(String name) {}
    }
    

    chain:中文含义是链式的,设置为true,则setter方法返回当前对象。如下

    @Data
    @Accessors(chain = true)
    public class User {
        private Long id;
        private String name;
    }
    

    编译查看字节码:mvn compile

    public class User {
        private Long id;
        private String name;
        
        // 生成的setter方法如下,方法体和其他方法略
        public User setId(Long id) {}
        public User setName(String name) {}
    }
    

    prefix:中文含义是前缀,用于生成getter和setter方法的字段名会忽视指定前缀(遵守驼峰命名)

    @Data
    @Accessors(prefix = "t")
    public class User {
        private Long tId;
        private String tName;
    }
    
    @Data
    @Accessors(prefix = {"p","t"})
    public class User {
        private Long tId;
        private String pName;
    }
    

    编译查看字节码(如上两种都编译后都会生成如下字节码):mvn compile

    public class User {
    	private Long pId;
    	private String pName;
    	
    	// 生成的getter和setter方法如下,方法体略
    	public Long getId() {}
    	public void setId(Long id) {}
    	public String getName() {}
    	public void setName(String name) {}
    }
    

    日志注解—@Slf4j/@Log4j

    @Slf4j:自动生成该类的log静态常量,直接使用,不用再手动 new log 静态常量了

    除了 @Slf4j 之外,lombok也提供其他日志框架的变种注解可以用,@Log4j、@Log...他们都是帮我们创建一个静态常量 log,只是使用的库不一样而已

    @Slf4j
    public class User {
        // 编译查看字节码:mvn compile
        private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(User.class);
        
        public static void main(String[] args) {
            log.info("lombok-->Slf4j");
        }
    }
    

    其他日志框架:

    @Slf4j //对应的log语句如下
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(User.class);
    
    @Log4j //对应的log语句如下
    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
    
    @Log //对应的log语句如下
    private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
    

    注意:必须引入对应的日志框架依赖

    SpringBoot默认支持的就是 slf4j + logback 的日志框架,所以也不用再多做啥设定,直接就可以用在 SpringBoot project上,log 系列注解最常用的就是 @Slf4j

    Lombok插件原理-对比反射技术

    讲解JSR介绍和lombok原理讲解

    • 熟悉Java自定义注解的同学已经猜到是: JSR 269插件化注解处理
    JSR 269:  Pluggable Annotation Processing API
    实现在Javac编译阶段利用“Annotation Processor”对自定义的注解进行预处理后生成真正在JVM上面执行的“Class文件
    地址:https://www.jcp.org/en/jsr/detail?id=269
    
    • 科普
    JSR是Java Specification Requests的缩写,意思是Java 规范提案。
    是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。
    任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
    
    • Lombok解析流程
    Javac 解析成AST抽象语法树后, Lombok根据自己编写的注解处理器,动态地修改 AST增加新的节点(即Lombok自定义注解所需要生成的代码),最终生成JVM可执行的字节码Class文件
    
    可以看编译后的在target目录下的class文件
    
    • 能实现上述效果的还有一个反射技术,那两个对比如何?
    使用Annotation Processing自定义注解是在编译阶段进行修改
    JDK的反射技术是在运行时动态修改
    
    结论:反射更加灵活一些但是带来的性能损耗更加大
    
  • 相关阅读:
    js18
    js17
    js16
    js15
    js14
    js13
    js12
    js11
    八月二十三的php
    八月二十二的php
  • 原文地址:https://www.cnblogs.com/liusuixing/p/14413636.html
Copyright © 2011-2022 走看看