lombok 订阅
Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。 展开全文
Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。
信息
外文名
Lombok
中文名
龙目
linux简介
“Boilerplate”是一个术语,用于描述在应用程序的许多部分中很少改动就重复的代码。对Java语言最常见的批评就是在大多数项目中都可以找到这种类型的代码,由于语言本身的局限性而更加严重。龙目岛计划(Project Lombok)旨在通过用简单的注释集代替众多的代码。Lombok也存在一定风险,在一些开发工具商店中没有Project Lombok支持选择。 IDE和JDK升级存在破裂的风险,并且围绕项目的目标和实施存在争议。常用注解:@Setter :注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。@Getter :使用方法同上,区别在于生成的是getter方法。@ToString :注解在类,添加toString方法。@EqualsAndHashCode: 注解在类,生成hashCode和equals方法。@NoArgsConstructor: 注解在类,生成无参的构造方法。@RequiredArgsConstructor: 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。@AllArgsConstructor: 注解在类,生成包含类中所有字段的构造方法。@Data: 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。@Slf4j: 注解在类,生成log变量,严格意义来说是常量。
收起全文
精华内容
下载资源
问答
  • lombok

    千次阅读 2020-01-09 00:03:27
    lombok

    https://projectlombok.org/


    1 IDEA使用lombok

    1.1 IDEA引入lombok插件

    1.2 Maven引入lombok

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
        <scope>provided</scope>
    </dependency>

    provided适合在编译和测试的环境,他和compile很接近,但是provide仅仅需要在编译和测试阶段,provide将不会被打包到lib目录下


    2 Lombok实现原理

    工作在编译时期

     

    查看编译后的Class文件

     IDEA直接在target目录下查看即可


    3 Lombok常用注解

     

    3.1 @Getter

    Student.java

    import lombok.AccessLevel;
    import lombok.Getter;
    import javax.validation.constraints.NotNull;
    
    /**
     * @Getter 为属性生成get方法
     *     1.作用在类上:为该类的所有属性都添加Getter方法
     *     2.作用在属性上:只为这个属性生成Getter方法
     */
    public class Student {
        /**
         * lazy:作用在final字段上 懒加载(调用getName方法的时候才会去加载)
         */
        @Getter(lazy = true)
        private final String schoolAddress = "北京市海淀区颐和园路5号";
    
        private String name;
        /**
         * value:设置访问级别
         * onMethod_:为生成的Get方法添加其他的注解
         */
        @Getter(
                value = AccessLevel.PRIVATE,
                onMethod_ = {@NotNull}
        )
        private Integer age;
    }

    Student.class 

    import java.util.concurrent.atomic.AtomicReference;
    import javax.validation.constraints.NotNull;
    
    public class Student {
        private final AtomicReference<Object> schoolAddress = new AtomicReference();
        private String name;
        private Integer age;
        public Student() {
        }
        public String getSchoolAddress() {
            Object value = this.schoolAddress.get();
            if (value == null) {
                synchronized(this.schoolAddress) {
                    value = this.schoolAddress.get();
                    if (value == null) {
                        String actualValue = "北京市海淀区颐和园路5号";
                        value = "北京市海淀区颐和园路5号" == null ? this.schoolAddress : "北京市海淀区颐和园路5号";
                        this.schoolAddress.set(value);
                    }
                }
            }
            return (String)((String)(value == this.schoolAddress ? null : value));
        }
        @NotNull
        private Integer getAge() {
            return this.age;
        }
    }

    3.2 @Setter

    Student.java

    import lombok.AccessLevel;
    import lombok.Setter;
    import javax.validation.constraints.NotNull;
    
    /**
     * @Setter 为属性生成set方法
     */
    public class Student {
        @Setter
        private String name;
        @Setter(
                value = AccessLevel.PRIVATE,
                onParam_ = {@NotNull}
        )
        private Integer age;
    }

    Student.class 

    import javax.validation.constraints.NotNull;
    public class Student {
        private String name;
        private Integer age;
        public Student() {
        }
        public void setName(String name) {
            this.name = name;
        }
        private void setAge(@NotNull Integer age) {
            this.age = age;
        }
    }

    3.3 @ToString

    Student.java  

    import lombok.Setter;
    import lombok.ToString;
    import org.junit.Test;
    
    /**
     * @ToString 生成toString方法
     *     1.作用在类上
     *     2.includeFieldNames:是否包含属性名
     *     3.exclude:排除属性
     *     4.of:指向属性生成(两个都写of>exclude,显示of的)
     *     5.callSuper:是否调用父类的toString方法
     *     6.doNotUseGetters:true(不会调用get方法来获取属性值,而是通过属性的名字来获取 如果get方法有业务逻辑将不会被触发)
     */
    @ToString(
            includeFieldNames = false,
            //exclude = {"name"},
            //of = {"age"},
            doNotUseGetters = true
    )
    public class Student {
        @Setter
        private String name;
        @Setter
        private Integer age;
        //观察是否调用了这个方法
        public Integer getAge() {
            System.out.println("调用get方法!");
            return this.age;
        }
    
        @Test
        public void test() {
            Student toStringTest = new Student();
            toStringTest.setName("小明");
            toStringTest.setAge(18);
            System.out.println(toStringTest.toString());
        }
    }

     Student.class 

    import org.junit.Test;
    public class Student {
        private String name;
        private Integer age;
        public Student() {
        }
        public Integer getAge() {
            System.out.println("调用get方法!");
            return this.age;
        }
        public String toString() {
            return "Student(" + this.name + ", " + this.age + ")";
        }
        public void setName(String name) {
            this.name = name;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Test
        public void test() {
            Student toStringTest = new Student();
            toStringTest.setName("小明");
            toStringTest.setAge(18);
            System.out.println(toStringTest.toString());
        }
    }

    3.4 @EqualsAndHashCode

    Student.java 

    import lombok.EqualsAndHashCode;
    
    /**
     * @EqualsAndHashCode 生成Equals方法和HashCode方法
     *     1.作用在类上
     *     2.exclude:排除的属性
     *     3.of:强制执行的属性
     *     4.callSuper:是否调用父类的Equals和HashCode方法
     *     5.doNotUseGetters:获取属性值的时候,是否调用属性的get方法
     *     6.onParam:生成方法的入参上添加自定义注解
     */
    @EqualsAndHashCode(
            exclude = {"age"}
    )
    public class Student {
        private String name;
        private Integer age;
    }

    Student.class  

    public class Student {
        private String name;
        private Integer age;
        public Student() {
        }
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof Student)) {
                return false;
            } else {
                Student other = (Student)o;
                if (!other.canEqual(this)) {
                    return false;
                } else {
                    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 Student;
        }
        public int hashCode() {
            int PRIME = true;
            int result = 1;
            Object $name = this.name;
            int result = result * 59 + ($name == null ? 43 : $name.hashCode());
            return result;
        }
    }
    

    3.5 @Data

    Student.java 

    import lombok.Data;
    
    /**
     * @Data 大而全的注解:包含@Getter,@Setter,@ToString,@EqualsAndHashCode
     */
    @Data
    public class Student {
        private String name;
        private Integer age;
    }

    Student.class  

    public class Student {
        private String name;
        private Integer age;
        public Student() {
        }
        public String getName() {
            return this.name;
        }
        public Integer getAge() {
            return this.age;
        }
        public void setName(String name) {
            this.name = name;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof Student)) {
                return false;
            } else {
                Student other = (Student)o;
                if (!other.canEqual(this)) {
                    return false;
                } else {
                    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;
                    }
                    Object this$age = this.getAge();
                    Object other$age = other.getAge();
                    if (this$age == null) {
                        if (other$age != null) {
                            return false;
                        }
                    } else if (!this$age.equals(other$age)) {
                        return false;
                    }
                    return true;
                }
            }
        }
        protected boolean canEqual(Object other) {
            return other instanceof Student;
        }
        public int hashCode() {
            int PRIME = true;
            int result = 1;
            Object $name = this.getName();
            int result = result * 59 + ($name == null ? 43 : $name.hashCode());
            Object $age = this.getAge();
            result = result * 59 + ($age == null ? 43 : $age.hashCode());
            return result;
        }
        public String toString() {
            return "Student(name=" + this.getName() + ", age=" + this.getAge() + ")";
        }
    }

    3.6 @Value 

    类属性会被编译成final的,因此只有get方法,而没有set方法

    import lombok.Value;
    @Value
    public class Student {
        private String name;
        private Integer age;
    }
    public final class Student {
        private final String name;
        private final Integer age;
        public Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return this.name;
        }
        public Integer getAge() {
            return this.age;
        }
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof Student)) {
                return false;
            } else {
                Student other = (Student)o;
                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;
                }
                Object this$age = this.getAge();
                Object other$age = other.getAge();
                if (this$age == null) {
                    if (other$age != null) {
                        return false;
                    }
                } else if (!this$age.equals(other$age)) {
                    return false;
                }
                return true;
            }
        }
        public int hashCode() {
            int PRIME = true;
            int result = 1;
            Object $name = this.getName();
            int result = result * 59 + ($name == null ? 43 : $name.hashCode());
            Object $age = this.getAge();
            result = result * 59 + ($age == null ? 43 : $age.hashCode());
            return result;
        }
        public String toString() {
            return "Student(name=" + this.getName() + ", age=" + this.getAge() + ")";
        }
    }
    

    3.7 @val 

    Student.java

    import lombok.val;
    import java.util.ArrayList;
    /**
     * @val 弱语言变量
     */
    public class Student {
        public Student() {
            val schoolAddress = "北京市海淀区颐和园路5号";
            val students = new ArrayList<>();
            students.add("张三");
        }
    }

    Student.class   

    import java.util.ArrayList;
    public class Student {
        public Student() {
            String schoolAddress = "北京市海淀区颐和园路5号";
            ArrayList<Object> students = new ArrayList();
            students.add("张三");
        }
    }

    3.8 @NonNull

    Student.java  

    import lombok.NonNull;
    /**
     * @NonNull 生成非空检查
     */
    public class Student {
        private String name;
        public Student(@NonNull String name) {
            this.name = name;
        }
    }

    Student.class   

    import lombok.NonNull;
    public class Student {
        private String name;
        public Student(@NonNull String name) {
            if (name == null) {
                throw new NullPointerException("name is marked non-null but is null");
            } else {
                this.name = name;
            }
        }
    }

    3.9 @AllArgsConstructor/@NoArgsConstructor/@RequiredArgsConstructor

    Student.java    

    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;
    /**
     * 1.@AllArgsConstructor:全参
     * 2.@NoArgsConstructor:无参
     * 3.@RequiredArgsConstructor:必要参数
     */
    @RequiredArgsConstructor
    public class Student {
        private final String schoolAddress;
        @NonNull
        private String name;
        private Integer age;
    }

    Student.class    

    import lombok.NonNull;
    public class Student {
        private final String schoolAddress;
        @NonNull
        private String name;
        private Integer age;
        public Student(String schoolAddress, @NonNull String name) {
            if (name == null) {
                throw new NullPointerException("name is marked non-null but is null");
            } else {
                this.schoolAddress = schoolAddress;
                this.name = name;
            }
        }
    }

    3.10 @Cleanup

    FileUtils.java

    import lombok.Cleanup;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    /**
     * @Cleanup 资源关闭
     */
    public class FileUtils {
        /**
         * 文件拷贝
         *
         * @param in  输入文件路径
         * @param out 输出文件路径
         */
        public static void copyFile(String in, String out) throws Exception {
            @Cleanup FileInputStream fileInputStream = new FileInputStream(in);
            @Cleanup FileOutputStream fileOutputStream = new FileOutputStream(out);
            int r;
            while ((r = fileInputStream.read()) != -1) {
                fileOutputStream.write(r);
            }
        }
    
        public static void main(String[] args) throws Exception {
            FileUtils.copyFile(".gitignore",".gitignore-copy");
        }
    }

     FileUtils.class

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.util.Collections;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.util.Collections;
    public class FileUtils {
        public FileUtils() {
        }
        public static void copyFile(String in, String out) throws Exception {
            FileInputStream fileInputStream = new FileInputStream(in);
            try {
                FileOutputStream fileOutputStream = new FileOutputStream(out);
                int r;
                try {
                    while((r = fileInputStream.read()) != -1) {
                        fileOutputStream.write(r);
                    }
                } finally {
                    if (Collections.singletonList(fileOutputStream).get(0) != null) {
                        fileOutputStream.close();
                    }
                }
            } finally {
                if (Collections.singletonList(fileInputStream).get(0) != null) {
                    fileInputStream.close();
                }
            }
        }
    
        public static void main(String[] args) throws Exception {
            copyFile(".gitignore", ".gitignore-copy");
        }
    }

    3.11 @Builder 

    Student.java

    import lombok.Builder;
    import lombok.ToString;
    
    @Builder
    @ToString
    public class Student {
        private String name;
        private Integer age;
    }

    Student.class

    public class Student {
        private String name;
        private Integer age;
        Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
        public static Student.StudentBuilder builder() {
            return new Student.StudentBuilder();
        }
        public String toString() {
            return "Student(name=" + this.name + ", age=" + this.age + ")";
        }
        public static class StudentBuilder {
            private String name;
            private Integer age;
            StudentBuilder() {
            }
            public Student.StudentBuilder name(String name) {
                this.name = name;
                return this;
            }
            public Student.StudentBuilder age(Integer age) {
                this.age = age;
                return this;
            }
            public Student build() {
                return new Student(this.name, this.age);
            }
            public String toString() {
                return "Student.StudentBuilder(name=" + this.name + ", age=" + this.age + ")";
            }
        }
    }
    Student stu = new Student
            .StudentBuilder()
            .age(18)
            .build();
    //!!! Student(name=null, age=18)
    System.out.println(stu);
    //Student(name=蔡徐坤, age=58)
    Student kunkun = new Student
            .StudentBuilder()
            .age(58)
            .name("蔡徐坤")
            .build();
    System.out.println(kunkun);

    使用默认值

    @Builder
    @ToString
    public class Student {
        // 该字段有一个默认值;
        private String schoolAddress = "北京市海淀区颐和园路5号";
    }
    public class Student {
        private String schoolAddress = "北京市海淀区颐和园路5号";
        Student(String schoolAddress) {
            this.schoolAddress = schoolAddress;
        }
        public static Student.StudentBuilder builder() {
            return new Student.StudentBuilder();
        }
        public String toString() {
            return "Student(schoolAddress=" + this.schoolAddress + ")";
        }
        public static class StudentBuilder {
            private String schoolAddress;
            StudentBuilder() {
            }
            public Student.StudentBuilder schoolAddress(String schoolAddress) {
                this.schoolAddress = schoolAddress;
                return this;
            }
            public Student build() {
                return new Student(this.schoolAddress);
            }
            public String toString() {
                return "Student.StudentBuilder(schoolAddress=" + this.schoolAddress + ")";
            }
        }
    }
    // 生成的student对象并没有使用status的默认值
    //Student(schoolAddress=北京市海淀区颐和园路5号)
    Student student = Student.builder().build();
    System.out.println(student);

    在StudentBuilder代码的build()方法中可以看出来,生成Student对象时的schoolAddress字段值是StudentBuilder中的schoolAddress字段值。所以如果不通过schoolAddress(String schoolAddress)方法显式的设置schoolAddress字段的话,最终生成的对象中的schoolAddress值是java中String的默认值null,而不是在Student类中规定的默认值北京市海淀区颐和园路5号

    @Builder
    @ToString
    public class Student {
        // 该字段有一个默认值;
        @Builder.Default
        private String schoolAddress = "北京市海淀区颐和园路5号";
    }
    public class Student {
        private String schoolAddress;
        // 返回schoolAddress的默认值 北京市海淀区颐和园路5号
        private static String $default$schoolAddress() {
            return "北京市海淀区颐和园路5号";
        }
        Student(String schoolAddress) {
            this.schoolAddress = schoolAddress;
        }
        public static Student.StudentBuilder builder() {
            return new Student.StudentBuilder();
        }
        public String toString() {
            return "Student(schoolAddress=" + this.schoolAddress + ")";
        }
        public static class StudentBuilder {
            private boolean schoolAddress$set;
            private String schoolAddress$value;
            StudentBuilder() {
            }
            public Student.StudentBuilder schoolAddress(String schoolAddress) {
                this.schoolAddress$value = schoolAddress;
                this.schoolAddress$set = true;
                return this;
            }
            public Student build() {
                String schoolAddress$value = this.schoolAddress$value;
                // 会判断schoolAddress是否被显式的set,如果没有被set,则使用默认值。
                if (!this.schoolAddress$set) {
                    // 获取Student类中status的默认值1
                    schoolAddress$value = Student.$default$schoolAddress();
                }
                return new Student(schoolAddress$value);
            }
            public String toString() {
                return "Student.StudentBuilder(schoolAddress$value=" + this.schoolAddress$value + ")";
            }
        }
    }

    可以看到Student类中有一个$default$schoolAddress()的方法,用来返回schoolAddress字段的默认值;然后再看StudentBuilder类,在build()方法的时候会判断是否显式的给status字段赋值,如果没有赋值则将schoolAddress字段设置成默认值

    1. 如果想让类中的字段默认值生效,需要使用@Default注解
    2. @Builder会生成一个全参的构造函数

    3.12 @Slf4j

    SpringBoot项目

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
        <scope>provided</scope>
    </dependency>

     普通项目

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
        <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.2.0</version>
        <scope>test</scope>
    </dependency>

     

    @Slf4j
    public class Main {
        public static void main(String[] args) {
            //默认日志级别为info
            log.info("info");
            log.debug("debug");
            log.info("info");
            log.error("error");
            log.warn("warn");
        }
    }

    离线安装:https://blog.csdn.net/yitian_z/article/details/104134410

    展开全文
  • Lombok

    千次阅读 2019-08-14 14:16:26
    Lombok介绍 Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量。 Lombok使用方法 Lombok的使用跟引用jar包一样,可以...

    Lombok介绍

    Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量。

    Lombok使用方法

    Lombok的使用跟引用jar包一样,可以在官网(https://projectlombok.org/download)下载jar包,也可以使用maven添加依赖:

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.4</version>
        <scope>provided</scope>
    </dependency>
    

    Lombok常用注解

    • @Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
    • @Getter 使用方法同上,区别在于生成的是getter方法。
    • @ToString 注解在类,添加toString方法。
    • @EqualsAndHashCode 注解在类,生成hashCode和equals方法。
    • @NoArgsConstructor 注解在类,生成无参的构造方法。
    • @RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
    • @AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
    • @Data 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
    • @Slf4j 注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);

    Lombok工作原理

    在Lombok使用的过程中,只需要添加相应的注解,无需再为此写任何代码。自动生成的代码到底是如何产生的呢?
    核心之处就是对于注解的解析上。JDK5引入了注解的同时,也提供了两种解析方式。

    运行时解析

    运行时能够解析的注解,必须将@Retention设置为RUNTIME,这样就可以通过反射拿到该注解。java.lang.reflect反射包中提供了一个接口AnnotatedElement,该接口定义了获取注解信息的几个方法,Class、Constructor、Field、Method、Package等都实现了该接口,对反射熟悉的朋友应该都会很熟悉这种解析方式。

    编译时解析

    编译时解析有两种机制,分别简单描述下:
    1)Annotation Processing Tool
    apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,apt被替换主要有2点原因:

    1.api都在com.sun.mirror非标准包下
    2.没有集成到javac中,需要额外运行

    2)Pluggable Annotation Processing API
    JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强,javac执行的过程如下:
    在这里插入图片描述

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

    1.javac对源代码进行分析,生成了一棵抽象语法树(AST)
    2.运行过程中调用实现了“JSR 269 API”的Lombok程序
    3.此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
    4.javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)

    通过读Lombok源码,发现对应注解的实现都在HandleXXX中,比如@Getter注解的实现在HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如Google Auto、Dagger等等。

    Lombok的优缺点

    优点:

    • 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率
    • 让代码变得简洁,不用过多的去关注相应的方法
    • 属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等

    缺点:

    • 不支持多种参数构造器的重载
    • 虽然省去了手动创建getter/setter方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度
    展开全文
  • 新来个技术总监,禁止我们使用Lombok

    万次阅读 多人点赞 2020-02-11 10:42:02
    我有个学弟,在一家小型...但是这些都不是我这个学弟和我吐槽的点,他真正和我吐槽的是,他很不能理解,这位新来的技术总监竟然禁止公司内部所有开发使用Lombok。但是又没给出十分明确的,可以让人信服的理由。 于...

    CSDN博客之星,期待你的投票,谢谢!
    CSDN博客之星,期待你的投票,谢谢!
    CSDN博客之星,期待你的投票,谢谢!

    我有个学弟,在一家小型互联网公司做Java后端开发,最近他们公司新来了一个技术总监,这位技术总监对技术细节很看重,一来公司之后就推出了很多"政策",比如定义了很多开发规范、日志规范、甚至是要求大家统一使用某一款IDE。

    但是这些都不是我这个学弟和我吐槽的点,他真正和我吐槽的是,他很不能理解,这位新来的技术总监竟然禁止公司内部所有开发使用Lombok。但是又没给出十分明确的,可以让人信服的理由。

    于是他来找我聊天,问我这个要求到底是否合理。关于这个事情,我认为这位技术总监的出发点是好的,但是做法未免有些极端。

    之所以说出发点是好的,是因为使用Lombok确实会带来很多问题,而且我个人在工作中也基本不主动使用。

    之所以说不主动使用,那是因为有些同事的代码还是使用了的,所以我也被迫的要安装Lombok的插件。

    既然聊到这个话题,就简单说说我的一些看法。

    Lombok有什么好处?

    Lombok是一款非常实用Java工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO)。它通过注释实现这一目的。

    如果大家对于Lombok比较了解的话,可以先跳过这一段,直接往后看,如果不是很熟悉的话,可以简单了解一下。

    想在项目中使用Lombok,需要三个步骤:

    一、IDE中安装Lombok插件

    目前Lombok支持多种IDE,其中包括主流的Eclips、Intellji IDEA、Myeclipse等都是支持的。

    在IDEA中安装方式如下:

    -w400

    二、导入相关依赖

    Lombok 支持使用多重构建工具进行导入依赖,目前主要支持maven、gardle、ant等均支持。

    如使用maven导入方式如下:

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>
    

    三、代码中使用注解

    Lombok精简代码的方式主要是通过注解来实现,其中常用的有@Data、@Getter/@Setter、@Builder、@NonNull等。

    如使用@Data注解,即可简单的定义一个Java Bean:

    import lombok.Data;
    @Data
    public class Menu {
        private String shopId;
        private String skuMenuId;
        private String skuName;
    }
    

    使用@Data注解在类上,相当于同时使用了@ToString、@EqualsAndHashCode、@Getter、@Setter和@RequiredArgsConstrutor这些注解,对于POJO类十分有用。

    即自动帮忙给例子中的Menu类中定义了toString、Getter、Setter等方法。

    通过上面的例子,大家可以发现,我们是使用@Data注解大大减少了代码量,使代码非常简洁。这也是很多开发者热衷于使用Lombok的主要原因。

    另外,关于Lombok的使用,不同人有不同的看法,因为很多人都使用过Lombok,对于他的优点都比较了解,所以接下来我们重点说一下Lombok的使用会带来哪些问题。

    Lombok有什么坏处?

    强X队友

    因为Lombok的使用要求开发者一定要在IDE中安装对应的插件。

    如果未安装插件的话,使用IDE打开一个基于Lombok的项目的话会提示找不到方法等错误。导致项目编译失败。

    也就是说,如果项目组中有一个人使用了Lombok,那么其他人就必须也要安装IDE插件。否则就没办法协同开发。

    更重要的是,如果我们定义的一个jar包中使用了Lombok,那么就要求所有依赖这个jar包的所有应用都必须安装插件,这种侵入性是很高的。

    代码可读性,可调试性低

    在代码中使用了Lombok,确实可以帮忙减少很多代码,因为Lombok会帮忙自动生成很多代码。

    但是这些代码是要在编译阶段才会生成的,所以在开发的过程中,其实很多代码其实是缺失的。

    在代码中大量使用Lombok,就导致代码的可读性会低很多,而且也会给代码调试带来一定的问题。

    比如,我们想要知道某个类中的某个属性的getter方法都被哪些类引用的话,就没那么简单了。

    有坑

    因为Lombok使代码开发非常简便,这就使得部分开发者对其产生过度依赖。

    在使用Lombok过程中,如果对于各种注解的底层原理不理解的话,很容易产生意想不到的结果。

    举一个简单的例子,我们知道,当我们使用@Data定义一个类的时候,会自动帮我们生成equals()方法 。

    但是如果只使用了@Data,而不使用@EqualsAndHashCode(callSuper=true)的话,会默认是@EqualsAndHashCode(callSuper=false),这时候生成的equals()方法只会比较子类的属性,不会考虑从父类继承的属性,无论父类属性访问权限是否开放。

    这就可能得到意想不到的结果。

    影响升级

    因为Lombok对于代码有很强的侵入性,就可能带来一个比较大的问题,那就是会影响我们对JDK的升级。

    按照如今JDK的升级频率,每半年都会推出一个新的版本,但是Lombok作为一个第三方工具,并且是由开源团队维护的,那么他的迭代速度是无法保证的。

    所以,如果我们需要升级到某个新版本的JDK的时候,若其中的特性在Lombok中不支持的话就会受到影响。

    还有一个可能带来的问题,就是Lombok自身的升级也会受到限制。

    因为一个应用可能依赖了多个jar包,而每个jar包可能又要依赖不同版本的Lombok,这就导致在应用中需要做版本仲裁,而我们知道,jar包版本仲裁是没那么容易的,而且发生问题的概率也很高。

    破坏封装性

    以上几个问题,我认为都是有办法可以避免的。但是有些人排斥使用Lombok还有一个重要的原因,那就是他会破坏封装性。

    众所周知,Java的三大特性包括封装性、继承性和多态性。

    如果我们在代码中直接使用Lombok,那么他会自动帮我们生成getter、setter 等方法,这就意味着,一个类中的所有参数都自动提供了设置和读取方法。

    举个简单的例子,我们定义一个购物车类:

    @Data
    public class ShoppingCart { 
        //商品数目
        private int itemsCount; 
        //总价格
        private double totalPrice; 
        //商品明细
        private List items = new ArrayList<>();
    }
    //例子来源于《极客时间-设计模式之美》
    

    我们知道,购物车中商品数目、商品明细以及总价格三者之前其实是有关联关系的,如果需要修改的话是要一起修改的。

    但是,我们使用了Lombok的@Data注解,对于itemsCount 和 totalPrice这两个属性。虽然我们将它们定义成 private 类型,但是提供了 public 的 getter、setter 方法。

    外部可以通过 setter 方法随意地修改这两个属性的值。我们可以随意调用 setter 方法,来重新设置 itemsCount、totalPrice 属性的值,这也会导致其跟 items 属性的值不一致。

    而面向对象封装的定义是:通过访问权限控制,隐藏内部数据,外部仅能通过类提供的有限的接口访问、修改内部数据。所以,暴露不应该暴露的 setter 方法,明显违反了面向对象的封装特性。

    好的做法应该是不提供getter/setter,而是只提供一个public的addItem方法,同时取修改itemsCount、totalPrice以及items三个属性。

    总结

    本文总结了常用的Java开发工具Lombok的优缺点。

    优点是使用注解即可帮忙自动生成代码,大大减少了代码量,使代码非常简洁。

    但是并不意味着Lombok的使用没有任何问题,在使用Lombok的过程中,还可能存在对队友不友好、对代码不友好、对调试不友好、对升级不友好等问题。

    最重要的是,使用Lombok还会导致破坏封装性的问题。

    虽然使用Lombok存在着很多方便,但是也带来了一些问题。

    但是到底建不建议在日常开发中使用,我其实保持一个中立的态度,不建议大家过度依赖,也不要求大家一定要彻底不用。

    只要大家在使用的过程中,或者评估要不要在代码中引入Lombok之前,在想到他的优点的同时,能够考虑到他给代码带来的问题的,那么本文的目的也就达到了!

    参考资料:

    https://time.geekbang.org/column/article/164907

    https://projectlombok.org/

    在这里插入图片描述

    展开全文
  • 接触Lombok @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsContructor。是Lombok插件三种生成不同构造方法的注解,来完成项目中不同构造方法的需求。 @NoArgsConstructor : 生成一个无参数的构造方法 ...

    接触Lombok

    @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor。是Lombok插件三种生成不同构造方法的注解,来完成项目中不同构造方法的需求。

    • @NoArgsConstructor : 生成一个无参数的构造方法
    • @AllArgsContructor: ?会生成一个包含所有变量
    • @RequiredArgsConstructor: 会生成一个包含常量,和标识了NotNull的变量的构造方法。生成的构造方法是私有的private。
    • 主要使用前两个注解,这样就不需要自己写构造方法,代码简洁规范。

    看Lombok注解的全貌

    Lombok是一个通过注解形式帮助构造简洁、规范的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。
    下载地址:
    github地址:https://github.com/rzwitserloot/lombok
    官方地址:https://projectlombok.org/。
    官方API : https://projectlombok.org/features/all

    在IDEA中使用它的过程

    • 安装
      这里写图片描述

    • Maven项目引入lombok的jar

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

    常用注解介绍

    • @Getter and @Setter
      可以用@Getter / @Setter注释字段(也可以注释到类上的—(在实体类中常用且推荐)),lombok会自动生成默认的Getter/Setter方法。

    • @ToString
      自动生成toString()方法,默认情况,按顺序(以“,”分隔)打印你的类名称以及每个字段。也可以设置不包含哪些字段/@ToString(exclude = {“id”,“name”})

    import lombok.ToString;
    @ToString(exclude = {"id","name"})
    public class User {
      private Integer id;
      private String name;
      private String phone;
    }
    实际生成的toString()方法
    public String toString(){
      return "User(phone=" + phone + ")";
    }
    
    
    • @Synchronized
      给方法加上同步锁,建议直接写在代码中Synchronized

    参考文章 链接:https://www.jianshu.com/p/365ea41b357 作者:缓慢移动的蜗牛 來源:简书

    展开全文
  • lombok_lombok.zip

    2021-10-11 23:21:49
    lombok_lombok.zip
  • lombok_lombok_源码

    2021-09-11 06:50:20
    java编程lombok.jar
  • Lombok 介绍

    万次阅读 多人点赞 2018-01-09 14:49:06
    Lombok使用 介绍 在项目中使用Lombok可以减少很多重复代码的书写。比如说getter/setter/toString等方法的编写。 IDEA中的安装 打开IDEA的Setting –> 选择Plugins选项 –> 选择Browse repositories –> 搜索...
  • eclipse安装lombok插件

    万次阅读 多人点赞 2018-03-21 14:27:14
    1、下载lombok.jar,lombok.jar官方下载地址:https://projectlombok.org/download 如果下载不了的话,下面是我个人的百度云资源: 链接:https://pan.baidu.com/s/1Eiwy0Kb6OxCDuZw0O268kg 提取码:ds77 2、...
  • 在eclipse下安装lombok

    万次阅读 2018-08-01 16:57:22
    安装lombok可以在实体类中通过注解的方式,不需要写get和set方法,简单方便 安装lombok有俩种办法 第一种 1.下载 lombok.jar 2.安装 (1)将lombok.jar移到eclipse的安装目录 (2)在eclipse.in文件最后加入...
  • lombok.jar;lombok.jar

    2019-05-06 14:14:12
    lombok.jar lombok.jar lombok.jar lombok.jar 亲测好用!!!
  • lombok_lombok_源码.zip

    2021-09-30 17:57:09
    lombok_lombok_源码.zip
  • lombok.jar lombok.jar

    2018-07-18 14:31:17
    lombok.jar文件,放到eclipse安装路径,该jar包也就是lombok插件的jar文件了  打开eclipse.ini文件,添加如下内容:  -javaagent:lombok.jar  -Xbootclasspath/a:lombok.jar 重启eclipse
  • Lombok的例子 Lombok项目
  • lombok插件

    2018-05-25 19:54:24
    lombok插件,-IDE安装Lombok插件提高开发效率。java开发插件。
  • lombok1.16.20

    2018-03-23 20:29:15
    改变:lombok配置键lombok.addJavaxGeneratedAnnotation现在默认为falsetrue而不是true。Oracle在JDK9的发布中打破了这个注解,迫使这个重大改变。 改变:lombok配置键lombok.anyConstructor....
  • Lombok:东Lombok项目

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 139,637
精华内容 55,854
关键字:

lombok