Lombok注解使用和Lombok原理

Lombok是一个Java库,它通过注解自动为类生成构造函数、getter/setter、equals、hashcode、toString等方法,减少了样板代码。文章详细介绍了Lombok如何利用JSR269API在编译时修改抽象语法树以生成所需方法,以及@NonNull、@Getter、@Setter、@NoArgsConstructor、@AllArgsConstructor、@RequiredArgsConstructor、@ToString、@EqualsAndHashCode、@Data、@Value等注解的用法和示例。此外,还提到了日志注解@Log及其变体,以及@SneakyThrows、@Synchronized等其他实用注解。

一、Lombok原理(参考网上的博客)

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

lombok本质上就是这样的一个实现了"JSR 269 API"的程序。在使用javac的过程中,Lombok支持了JSR 269 Pluable Annotation Processing API(JSR 269 可插入注解过程接口),实现了JSR 269 API ,在编译时,Javac编译源码的具体流程如下:
在这里插入图片描述
在这里插入图片描述

首先有源代码,javac对源代码进行分析,生成一棵抽象语法树AST,运行过程中调用了实现了JSR 269 API 规范的Lombok程序,即Lombok Annotation Proceesor (Lombok 注解的处理器)。这时候,Lombok Annotation Processor对刚刚生成的AST进行处理,交递给Lombok Annotation Handler,Lombok Annotation Handler负责找到Lombok注解所在的类对应的语法树,然后修改该语法树(修改的内容为在AST中增加了set get 或其他方法定义的相应树节点),Lombok Annotation Processor这个处理器之后输出修改后的抽象语法树,拿到修改后的语法树后,最后进行解析和生成字节码文件。

步骤:

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

二、lombok注解

@Getter

给所有字段生成getter方法

有一个不太常用的功能
@Getter(lazy = true)
标注字段为懒加载字段,懒加载字段在创建对象时不会进行初始化,而是在第一次访问的时候才会初始化,后面再次访问也不会重复初始化
在这里插入图片描述

对照代码:

public class LombokDemo {
    private final List<String> list = getListFromCache();

    private List<String> getListFromCache() {
        System.out.println("getListFromCache");
        return new ArrayList<>();
    }

    public static void main(String[] args) {
        LombokDemo lombokDemo = new LombokDemo();
        System.out.println("-----------");
        System.out::println(lombokDemo.list);
    }
}

运行main方法,初始化对象LombokDemo时,会调用getListFromCache()方法,如下图所示:
在这里插入图片描述

代码:

public class LombokDemo {
    @Getter(lazy = true)
    private final List<String> list = getListFromCache();

    private List<String> getListFromCache() {
        System.out.println("getListFromCache");
        return new ArrayList<>();
    }

    public static void main(String[] args) {
        LombokDemo lombokDemo = new LombokDemo();
        System.out.println("-----------");
        lombokDemo.getList(); // 使用注解 @Getter(lazy = true)后会生成这样一个getter方法
    }
}

生成:

public class LombokDemo {
    private final AtomicReference<Object> list = new AtomicReference();

    public LombokDemo() {
    }

    private List<String> getListFromCache() {
        System.out.println("getListFromCache");
        return new ArrayList();
    }

    public static void main(String[] args) {
        LombokDemo lombokDemo = new LombokDemo();
        System.out.println("-----------");
        lombokDemo.getList();
    }

    public List<String> getList() {
        Object value = this.list.get();
        if (value == null) {
            synchronized(this.list) {
                value = this.list.get();
                if (value == null) {
                    List<String> actualValue = this.getListFromCache();
                    value = actualValue == null ? this.list : actualValue;
                    this.list.set(value);
                }
            }
        }

        return (List)((List)(value == this.list ? null : value));
    }
}

@Setter

给所有字段生成setter方法

注意:可以注解到字段或者类上(注解在类上会为类中的所有字段生成Getter和Setter方法),默认是public类型的,如果需要的话可以修改方法的访问级别。

如:

public class Emp {
    @Getter
    private Integer empno;

    @Getter(AccessLevel.PROTECTED)
    private String ename;

    @Setter(AccessLevel.PRIVATE)
    private String job;

    @Getter
    @Setter
    private Integer mgr;

    private LocalDate hiredate;
}
@Getter
@Setter
public class User {
	private String name;
	private Integer age;
	private String sn;
	private Long id;
	private String username;
	private String password;
}

@NonNull

判断是否为空,如果为空,则抛出java.lang.NullPointerException

@Getter
@Setter
public class Emp {
    @NonNull
    private Integer empno;
    private String ename;
}

生成:

public class Emp {
    @NonNull
    private Integer empno;
    private String ename;

    public Emp() {
    }
    
    @NonNull
    public Integer getEmpno() {
        return this.empno;
    }

    public void setEmpno(@NonNull Integer empno) {
        if (empno == null) {
            throw new NullPointerException("empno is marked non-null but is null");
        } else {
            this.empno = empno;
        }
    }

    public String getEname() {
        return this.ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }
}

@NoArgsConstructor

自动生成无参数构造函数。

生成一个无参构造方法。当类中有final字段没有被初始化时,编译器会报错,此时可用@NoArgsConstructor(force = true),然后就会为没有初始化的final字段设置默认值 0 / false / null, 这样编译器就不会报错。
对于具有约束的字段(例如@NonNull字段),不会生成检查或分配,因此请注意,正确初始化这些字段之前,这些约束无效。

final字段未初始化编译器报错:
在这里插入图片描述

@Setter
@NoArgsConstructor(force = true)
public class Emp {
    @NonNull
    private Integer empno;

    private final String ename;
}

生成:

public class Emp {
    @NonNull
    private Integer empno;
    private final String ename = null;

    public static void main(String[] args) {
        System.out.println(5);
    }

    public void setEmpno(@NonNull Integer empno) {
        if (empno == null) {
            throw new NullPointerException("empno is marked non-null but is null");
        } else {
            this.empno = empno;
        }
    }

    public Emp() {
    }
}

@RequiredArgsConstructor

生成构造方法(可能带参数也可能不带参数),如果带参数,这参数只能是以final修饰的未经初始化的字段,

也可以与NonNull配合使用,以@NonNull注解的未经初始化的字段。

@RequiredArgsConstructor(staticName = “of”)会生成一个of()的静态方法,并把构造方法设置为私有的

示例一:生成不带参数的构造方法

@RequiredArgsConstructor
public class Emp {
    private Integer empno;

    private String ename;

    private String job;

    private Integer mgr;

    private LocalDate hiredate;
}

生成代码:

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private LocalDate hiredate;

    public static void main(String[] args) {
        System.out.println(5);
    }

    public Emp() {
    }
}

示例二:参数只能是以final修饰的未经初始化的字段,或者是以@NonNull注解的未经初始化的字段

源代码

@RequiredArgsConstructor
public class Emp {
    @NotNull
    private Integer empno;

    @NotNull
    private String ename = "zhangsan";

    private final String job;

    private final Integer mgr =1234;

    private LocalDate hiredate;
}

生成代码:

public class Emp {
    @NotNull
    private Integer empno;
    @NotNull
    private String ename;
    private final String job;
    private final Integer mgr;
    private LocalDate hiredate;

    public Emp(@NotNull Integer empno, String job) {
        if (empno == null) {
            $$$reportNull$$$0(0);
        }

        super();
        this.ename = "zhangsan";
        this.mgr = 1234;
        if (empno == null) {
            throw new NullPointerException("empno is marked non-null but is null");
        } else {
            this.empno = empno;
            this.job = job;
        }
    }
}

示例三:生成一个of()的静态方法,并把构造方法设置为私有

源代码

@RequiredArgsConstructor( staticName = "of")
public class Emp {
    @NotNull
    private Integer empno;

    @NotNull
    private String ename = "zhangsan";

    private final String job;

    private final Integer mgr =1234;

    private LocalDate hiredate;
}

生成代码:

public class Emp {
    @NotNull
    private Integer empno;
    @NotNull
    private String ename;
    private final String job;
    private final Integer mgr;
    private LocalDate hiredate;

    private Emp(@NotNull Integer empno, String job) {
        if (empno == null) {
            $$$reportNull$$$0(0);
        }

        super();
        this.ename = "zhangsan";
        this.mgr = 1234;
        if (empno == null) {
            throw new NullPointerException("empno is marked non-null but is null");
        } else {
            this.empno = empno;
            this.job = job;
        }
    }

    public static Emp of(@NotNull Integer empno, String job) {
        if (empno == null) {
            $$$reportNull$$$0(1);
        }

        return new Emp(empno, job);
    }
}

@AllArgsConstructor

自动生成全参数构造函数。

注意下面的代码,加上字段加上final修饰和@NonNull注解后的效果:

@AllArgsConstructor
public class Emp {
    @NotNull
    private Integer empno;

    @NotNull
    private String ename = "zhangsan";

    private final String job;

    private final Integer mgr =1234; //不会出现在生成的构造方法中

    private LocalDate hiredate;
}

生成:

public class Emp {
    @NotNull
    private Integer empno;
    @NotNull
    private String ename;
    private final String job;
    private final Integer mgr;
    private LocalDate hiredate;
    
    public Emp(@NotNull Integer empno, @NotNull String ename, String job, LocalDate hiredate) {
        if (empno == null) {
            $$$reportNull$$$0(0);
        }

        if (ename == null) {
            $$$reportNull$$$0(1);
        }

        super();
        this.ename = "zhangsan";
        this.mgr = 1234;
        if (empno == null) {
            throw new NullPointerException("empno is marked non-null but is null");
        } else if (ename == null) {
            throw new NullPointerException("ename is marked non-null but is null");
        } else {
            this.empno = empno;
            this.ename = ename;
            this.job = job;
            this.hiredate = hiredate;
        }
    }
}

注意:如果要同时生成默认构造方法、指定参数构造方法、全参构造方法,可以采用Lombok自动生成无参和全参的构造方法的注解,然后手工添加指定参数的构造方法

@ToString

调用toString()方法的时候,输出类的所有属性值

该注解有以下多个属性可以进一步设置:
callSuper:是否输出父类的toString方法,默认为false
includeFieldNames:是否包含字段名称,默认为true
exclude:排除生成tostring的字段

1、生成toString()方法,默认情况下它会按顺序(以逗号分隔)打印你的类名称以及每个字段。
还可以设置不包含哪些字段,可以指定一个也可以指定多个

2、@ToString(exclude = “id”) / @ToString(exclude = {“id”,“name”})

3、如果继承的有父类的话,可以设置callSuper 让其调用父类的toString()方法,例如:@ToString(callSuper = true)

exclude使用:

@ToString(exclude = {"hiredate","job"})
public class Emp {
    private Integer empno;
    private String ename;

    private String job;

    private Integer mgr;

    private LocalDate hiredate;
}

生成:

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private LocalDate hiredate;

    public Emp() {
    }

    public String toString() {
        return "Emp(empno=" + this.empno + ", ename=" + this.ename + ", mgr=" + this.mgr + ")";
    }
}

callSuper:

@ToString(exclude = {"hiredate","job"},callSuper = true)
public class Emp {
    private Integer empno;
    private String ename;

    private String job;

    private Integer mgr;

    private LocalDate hiredate;

    public static void main(String[] args) {
        System.out.println(3 + 2);
    }
}

生成:

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private LocalDate hiredate;

    public Emp() {
    }

    public static void main(String[] args) {
        System.out.println(5);
    }

    public String toString() {
        return "Emp(super=" + super.toString() + ", empno=" + this.empno + ", ename=" + this.ename + ", mgr=" + this.mgr + ")";
    }
}

@EqualsAndHashCode

生成equals和hashCode方法

注意:
默认使用非静态的属性
可以通过exclude参数排除不需要生成的属性
可以通过of参数指定需要生成的属性
它默认不调用父类方法,只使用本类定义的属性进行操作,可以使用callSuper=true来解决,@Data中包含了@EqualsAndHashCode,使用callSuper属性参考@Data

1、

@EqualsAndHashCode
public class Emp {
    private Integer empno;
    private String ename;

    private static String job;

    private Integer mgr;

    private transient LocalDate hiredate;
}

生成:

public class Emp {
    private Integer empno;
    private String ename;
    private static String job;
    private Integer mgr;
    private transient LocalDate hiredate;

    public Emp() {
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Emp)) {
            return false;
        } else {
            Emp other = (Emp)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                label47: {
                    Object this$empno = this.empno;
                    Object other$empno = other.empno;
                    if (this$empno == null) {
                        if (other$empno == null) {
                            break label47;
                        }
                    } else if (this$empno.equals(other$empno)) {
                        break label47;
                    }

                    return false;
                }

                Object this$ename = this.ename;
                Object other$ename = other.ename;
                if (this$ename == null) {
                    if (other$ename != null) {
                        return false;
                    }
                } else if (!this$ename.equals(other$ename)) {
                    return false;
                }

                Object this$mgr = this.mgr;
                Object other$mgr = other.mgr;
                if (this$mgr == null) {
                    if (other$mgr != null) {
                        return false;
                    }
                } else if (!this$mgr.equals(other$mgr)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof Emp;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $empno = this.empno;
        int result = result * 59 + ($empno == null ? 43 : $empno.hashCode());
        Object $ename = this.ename;
        result = result * 59 + ($ename == null ? 43 : $ename.hashCode());
        Object $mgr = this.mgr;
        result = result * 59 + ($mgr == null ? 43 : $mgr.hashCode());
        return result;
    }
}

2、exclude 排除字段

@EqualsAndHashCode(exclude = {"mgr","hiredate"})
public class Emp {
    private Integer empno;
    private String ename;

    private  String job;

    private Integer mgr;

    private  LocalDate hiredate;
}

生成:

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private LocalDate hiredate;

    public Emp() {
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Emp)) {
            return false;
        } else {
            Emp other = (Emp)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                label47: {
                    Object this$empno = this.empno;
                    Object other$empno = other.empno;
                    if (this$empno == null) {
                        if (other$empno == null) {
                            break label47;
                        }
                    } else if (this$empno.equals(other$empno)) {
                        break label47;
                    }

                    return false;
                }

                Object this$ename = this.ename;
                Object other$ename = other.ename;
                if (this$ename == null) {
                    if (other$ename != null) {
                        return false;
                    }
                } else if (!this$ename.equals(other$ename)) {
                    return false;
                }

                Object this$job = this.job;
                Object other$job = other.job;
                if (this$job == null) {
                    if (other$job != null) {
                        return false;
                    }
                } else if (!this$job.equals(other$job)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof Emp;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $empno = this.empno;
        int result = result * 59 + ($empno == null ? 43 : $empno.hashCode());
        Object $ename = this.ename;
        result = result * 59 + ($ename == null ? 43 : $ename.hashCode());
        Object $job = this.job;
        result = result * 59 + ($job == null ? 43 : $job.hashCode());
        return result;
    }
}

of 指定要包含的字段
源代码:

@EqualsAndHashCode(of = {"mgr","hiredate"})
public class Emp {
    private Integer empno;
    private String ename;

    private  String job;

    private Integer mgr;

    private  LocalDate hiredate;
}

生成:

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private LocalDate hiredate;

    public Emp() {
    }

    public static void main(String[] args) {
        System.out.println(5);
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Emp)) {
            return false;
        } else {
            Emp other = (Emp)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$mgr = this.mgr;
                Object other$mgr = other.mgr;
                if (this$mgr == null) {
                    if (other$mgr != null) {
                        return false;
                    }
                } else if (!this$mgr.equals(other$mgr)) {
                    return false;
                }

                Object this$hiredate = this.hiredate;
                Object other$hiredate = other.hiredate;
                if (this$hiredate == null) {
                    if (other$hiredate != null) {
                        return false;
                    }
                } else if (!this$hiredate.equals(other$hiredate)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof Emp;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $mgr = this.mgr;
        int result = result * 59 + ($mgr == null ? 43 : $mgr.hashCode());
        Object $hiredate = this.hiredate;
        result = result * 59 + ($hiredate == null ? 43 : $hiredate.hashCode());
        return result;
    }
}

@Data

相当于五个注解:@Getter,@Setter,@ToString,@EqualsAndHashCode,@RequiredArgsConstrutor

@Value

作用于类,是以下注解的集合:@ToString @EqualsAndHashCode @Getter @RequiredArgsConstructor

(注意只有Getter没有Setter)

并且会将字段都变成不可变类型:使用final修饰

代码:

@Value
public class Emp {
    private Integer empno;
    private String ename;

    private  String job;

    private Integer mgr;

    private  LocalDate hiredate;
}

生成:

public final class Emp {
    private final Integer empno;
    private final String ename;
    private final String job;
    private final Integer mgr;
    private final LocalDate hiredate;

    public Emp(Integer empno, String ename, String job, Integer mgr, LocalDate hiredate) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.mgr = mgr;
        this.hiredate = hiredate;
    }

    public Integer getEmpno() {
        return this.empno;
    }

    public String getEname() {
        return this.ename;
    }

    public String getJob() {
        return this.job;
    }

    public Integer getMgr() {
        return this.mgr;
    }

    public LocalDate getHiredate() {
        return this.hiredate;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Emp)) {
            return false;
        } else {
            Emp other = (Emp)o;
            Object this$empno = this.getEmpno();
            Object other$empno = other.getEmpno();
            if (this$empno == null) {
                if (other$empno != null) {
                    return false;
                }
            } else if (!this$empno.equals(other$empno)) {
                return false;
            }

            label61: {
                Object this$ename = this.getEname();
                Object other$ename = other.getEname();
                if (this$ename == null) {
                    if (other$ename == null) {
                        break label61;
                    }
                } else if (this$ename.equals(other$ename)) {
                    break label61;
                }

                return false;
            }

            label54: {
                Object this$job = this.getJob();
                Object other$job = other.getJob();
                if (this$job == null) {
                    if (other$job == null) {
                        break label54;
                    }
                } else if (this$job.equals(other$job)) {
                    break label54;
                }

                return false;
            }

            Object this$mgr = this.getMgr();
            Object other$mgr = other.getMgr();
            if (this$mgr == null) {
                if (other$mgr != null) {
                    return false;
                }
            } else if (!this$mgr.equals(other$mgr)) {
                return false;
            }

            Object this$hiredate = this.getHiredate();
            Object other$hiredate = other.getHiredate();
            if (this$hiredate == null) {
                if (other$hiredate != null) {
                    return false;
                }
            } else if (!this$hiredate.equals(other$hiredate)) {
                return false;
            }

            return true;
        }
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $empno = this.getEmpno();
        int result = result * 59 + ($empno == null ? 43 : $empno.hashCode());
        Object $ename = this.getEname();
        result = result * 59 + ($ename == null ? 43 : $ename.hashCode());
        Object $job = this.getJob();
        result = result * 59 + ($job == null ? 43 : $job.hashCode());
        Object $mgr = this.getMgr();
        result = result * 59 + ($mgr == null ? 43 : $mgr.hashCode());
        Object $hiredate = this.getHiredate();
        result = result * 59 + ($hiredate == null ? 43 : $hiredate.hashCode());
        return result;
    }

    public String toString() {
        return "Emp(empno=" + this.getEmpno() + ", ename=" + this.getEname() + ", job=" + this.getJob() + ", mgr=" + this.getMgr() + ", hiredate=" + this.getHiredate() + ")";
    }
}

@Log

生成log对象,用于记录日志,可以通过topic属性来设置getLogger(String name)方法的参数 例如 @Log4j(topic = “com.xxx.entity.User”),默认是类的全限定名,即 类名.class,log支持以下几种:

@Log java.util.logging.Logger
@Log4j org.apache.log4j.Logger
@Log4j2 org.apache.logging.log4j.Logger
@Slf4j org.slf4j.Logger
@XSlf4j org.slf4j.ext.XLogger
@CommonsLog org.apache.commons.logging.Log
@JBossLog org.jboss.logging.Logger

示例一:
Maven依赖:

 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-access</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

代码:

package com.hc.domain;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Emp {
    public static void main(String[] args) {
        log.info("info","hahaa");
    }
}

生成:

package com.hc.domain;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Emp {
    private static final Logger log = LoggerFactory.getLogger(Emp.class);

    public Emp() {
    }

    public static void main(String[] args) {
        log.info("info", "hahaa");
    }
}

结果:
在这里插入图片描述
实例二:
代码:

package com.hc.domain;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "com.hc.demo")
public class Emp {
    public static void main(String[] args) {
        log.info("info","hahaa");
    }
}

生成:

package com.hc.domain;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Emp {
    private static final Logger log = LoggerFactory.getLogger("com.hc.demo");
    public Emp() {
    }
    public static void main(String[] args) {
        log.info("info", "hahaa");
    }
}

结果:
在这里插入图片描述

@SneakyThrows

贴上注解的方法可以省略try-catch

代码:

public class LombokDemo {
    @SneakyThrows
    public void fun1(){
        Thread.sleep(1000);
    }
    @SneakyThrows(InterruptedException.class)
    public void fun2(){
        Thread.sleep(1000);
    }
}

生成:

public class LombokDemo {
    public LombokDemo() {
    }

    public void fun1() {
        try {
            Thread.sleep(1000L);
        } catch (Throwable var2) {
            throw var2;
        }
    }

    public void fun2() {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException var2) {
            throw var2;
        }
    }
}

@Synchronized

给方法加上同步锁,作用在方法上,自动添加到同步机制,生成的代码并不是直接锁方法而是锁代码块

注意static方法/普通方法/指定lock对象的三种区别
代码:

public class LombokDemo {
    @Synchronized
    public void fun1() {
        System.out.println("fun1");
    }

    private final Object readLock = new Object();

    @Synchronized("readLock")
    public void fun2() {
        System.out.println("fun1");
    }

    @Synchronized
    public static void fun3() {
        System.out.println("fun1");
    }
}

生成:

public class LombokDemo {
    private final Object $lock = new Object[0];
    private static final Object $LOCK = new Object[0];
    private final Object readLock = new Object();

    public LombokDemo() {
    }

    public void fun1() {
        synchronized(this.$lock) {
            System.out.println("fun1");
        }
    }

    public void fun2() {
        synchronized(this.readLock) {
            System.out.println("fun1");
        }
    }

    public static void fun3() {
        synchronized($LOCK) {
            System.out.println("fun1");
        }
    }
}

@Cleanup

用于确保已分配的资源被释放,自动帮我们调用close()方法。比如IO的连接关闭。

主要用来修饰 IO 流相关类, 会在 finally 代码块中对该资源进行 close();

代码:

public class LombokDemo {

    public static void fileCopy(File sources, File aim) throws IOException {// psvm
        @Cleanup FileInputStream fis = new FileInputStream(sources);
        @Cleanup FileOutputStream fos = new FileOutputStream(aim);
        byte[] buf = new byte[256];
        int len = -1;
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
    }
}

生成:

public class LombokDemo {

    public static void fileCopy(File sources, File aim) throws IOException {// psvm
        @Cleanup FileInputStream fis = new FileInputStream(sources);
        @Cleanup FileOutputStream fos = new FileOutputStream(aim);
        byte[] buf = new byte[256];
        int len = -1;
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
    }
}

@Delegate

为List类型的字段生成一大堆常用的方法,其实这些方法都是List中的方法

源代码:

public class LombokDemo {
    @Delegate
    private  List<String> list ;
}

生成:

public class LombokDemo {
    private List<String> list;

    public LombokDemo() {
    }

    public static void main(String[] args) {
    }

    public int size() {
        return this.list.size();
    }

    public boolean isEmpty() {
        return this.list.isEmpty();
    }

    public boolean contains(Object arg0) {
        return this.list.contains(arg0);
    }

    public Iterator<String> iterator() {
        return this.list.iterator();
    }

    public Object[] toArray() {
        return this.list.toArray();
    }

    public <T> T[] toArray(T[] arg0) {
        return this.list.toArray(arg0);
    }

    public boolean add(String arg0) {
        return this.list.add(arg0);
    }

    public boolean remove(Object arg0) {
        return this.list.remove(arg0);
    }

    public boolean containsAll(Collection<?> arg0) {
        return this.list.containsAll(arg0);
    }

    public boolean addAll(Collection<? extends String> arg0) {
        return this.list.addAll(arg0);
    }

    public boolean addAll(int arg0, Collection<? extends String> arg1) {
        return this.list.addAll(arg0, arg1);
    }

    public boolean removeAll(Collection<?> arg0) {
        return this.list.removeAll(arg0);
    }

    public boolean retainAll(Collection<?> arg0) {
        return this.list.retainAll(arg0);
    }

    public void replaceAll(UnaryOperator<String> arg0) {
        this.list.replaceAll(arg0);
    }

    public void sort(Comparator<? super String> arg0) {
        this.list.sort(arg0);
    }

    public void clear() {
        this.list.clear();
    }

    public String get(int arg0) {
        return (String)this.list.get(arg0);
    }

    public String set(int arg0, String arg1) {
        return (String)this.list.set(arg0, arg1);
    }

    public void add(int arg0, String arg1) {
        this.list.add(arg0, arg1);
    }

    public String remove(int arg0) {
        return (String)this.list.remove(arg0);
    }

    public int indexOf(Object arg0) {
        return this.list.indexOf(arg0);
    }

    public int lastIndexOf(Object arg0) {
        return this.list.lastIndexOf(arg0);
    }

    public ListIterator<String> listIterator() {
        return this.list.listIterator();
    }

    public ListIterator<String> listIterator(int arg0) {
        return this.list.listIterator(arg0);
    }

    public List<String> subList(int arg0, int arg1) {
        return this.list.subList(arg0, arg1);
    }

    public Spliterator<String> spliterator() {
        return this.list.spliterator();
    }
}

注意:一个类中只能使用一个@Delegate注解,因为使用多个会生成多个size()方法,从而会编译报错。

@Builder

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

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class LombokBuilder {
    private int id;
    private String name;
}

public class TestMain {
    public static void main(String[] args) {
        LombokBuilder lombokBuilder = LombokBuilder.builder().id(2).build();
    }
}

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

@SuperBuilder

@SuperBuilder
@Data
public class LombokBuilderParent {
    private String value;
}

@Data
@SuperBuilder
public class LombokBuilder extends LombokBuilderParent{
    private int id;
    private String name;
}

剩余注解总览:

基本注解的使用(注解属性非必选)

@AllArgsConstructor:作用于类,生成参数为所有实例变量的构造函数
@Builder:作用于类,将其变成建造者模式
@Cleanup:作用于变量,自动关闭资源,针对实现了 java.io.Closeable 接口的对象有效
@CustomLog:自定义日志类,生成 log 对象
@Data:作用于类,是以下注解的集合:@ToString @EqualsAndHashCode @Getter @Setter @RequiredArgsConstructor
@EqualsAndHashCode:作用于类,覆盖默认的 equals 和 hashCode1
@Generated:用于标记类、变量、方法是自动生成的,没什么大用
@Getter:作用于类,生成该类所有的实例变量的 getter 方法。作用于变量,生成变量的 getter 方法
@NoArgsConstructor:作用于类,生成无参构造方法
@NonNull:作用于成员变量和参数中,标识不能为空,否则抛出空指针异常
@RequiredArgsConstructor:作用于类,生成包含 final 和 @NonNull 注解的成员变量的构造方法
@Setter:作用于类,生成该类所有的实例变量的 setter 方法。作用于变量,生成该变量的 setter 方法
@Singular:作用于集合字段,需要配合 @Builder 使用2
@SneakyThrows:作用于方法,对异常进行捕捉并抛出
@Synchronized:作用于方法,可以替换 synchronized 关键字或 lock 锁
@ToString:作用于类,覆盖默认的 toString() 方法
@val:作用于类、变量,主要用于声明变量的类型,注解将从初始化程序表达式中推断类型,生成的变量是 final 不可以变
@Value:作用于类,是以下注解的集合:@ToString @EqualsAndHashCode @Getter @RequiredArgsConstructor
@var:和 @val 一样,两者区别在于 var 不加 final
@With:作用于类、变量,生成 with + 变量名的方法,返回当前对象

外部注解的使用

@CommonsLog,@Log,@JBossLog,@Log4j,@Log4j2,@Slf4j,@XSlf4j:日志注解,作用于类

实验性注解的使用

@Accessors:类似于 @Builder 支持链式调用,需要配合 @Setter、@Getter 等注解使用,作用于类、变量
@Delegate:作用于容器变量,为该变量生成一堆常用的方法,这些方法都是容器中的方法
@ExtensionMethod:作用于类,向类添加方法,无需创建新的子类
@FieldDefaults:作用于类,定义变量的访问修饰符以及是否加 final
@FieldNameConstants:作用于类,生成一个包含所有成员变量的内部类或者内部枚举,内部类中每个字段值即为字段名并且值不可变
@Helper:作用于方法内部类,使内部类中的方法暴露在外面可以被直接调用,不建议使用
@NonFinal:作用于类、变量,表示变量不加 final
@PackagePrivate:作用于类和变量,相当于访问修饰符的 default,没什么用
@SuperBuilder:支持对于基类成员变量赋值,算是 @Builder 的升级版
@Tolerate:实现对冲突的兼容,作用于方法上,没什么大用,可以配合 @Builder 使用
@UtilityClass:作用于类,将类标记为 final,并且类、内部类中的方法、字段都标记为 static
@WithBy3

基于 v1.18.22 版本的实验性注解

@StandardException:自定义异常类

待完善的

@EqualsAndHashCode.Include(replaces = “”)

@Singular 中的 ignoreNullCollections 属性待完善

@WithBy

优缺点

Lombok 的优缺点

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

缺点:
不支持多种参数构造器的重载
虽然省去了手动创建一系列方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度

常用

使用lombok最多的地方就是实体类了
@Data
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder (实体类如果有继承慎用)
@Accessors (设置值的链式调用,看个人习惯)

其它常用
@Slf4j (打印日志)
@CleanUp (关闭资源)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值