lombok

一、Lombok背景介绍

官方介绍如下:

Project Lombok makes java a spicier language by adding 'handlers' that know how to build and compile simple, boilerplate-free, not-quite-java code.

大致意思是Lombok通过增加一些“处理程序”,可以让java变得简洁、快速。

二、Lombok安装

Lombok的使用非常简单:

2.1、引入相应的maven包

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

2.2、添加IDE工具对Lombok的支持

IDEA中引入Lombok支持如下:

点击File-- Settings设置界面,安装Lombok插件:

img

点击File-- Settings设置界面,开启 AnnocationProcessors: 开启该项是为了让Lombok注解在编译阶段起到作用。 img

Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。

Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。

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

三、Lombok使用详解

Lombok 提供注解方式来提高代码的简洁性,常用注解概览:

  • val:用在局部变量前面,相当于将变量声明为final
  • @Data:注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法,相当于同时加上以下注解@Setter @Getter,@ToString,@EqualsAndHashCode
  • @Value: 用在类上,是@Data的不可变形式,相当于为属性添加final声明,只提供getter方法,而不提供setter方法
  • @Setter、@Getter:注解在类和属性上;为属性提供 setting、getting 方法
  • @Getter(lazy=true) : 可以替代经典的Double Check Lock样板代码
  • @ToString:生成toString方法,默认情况下,会输出类名、所有属性,属性按照顺序输出,以逗号分割。
  • @EqualsAndHashCode:实现equals()方法和hashCode()方法
  • @Builder:构建 建造者模式
  • @NonNull:该注解快速判断是否为空,如果为空,则抛出java.lang.NullPointerException
  • @Synchronized:该注解自动添加到同步机制,有趣的是,生成的代码并不是直接锁方法,而是锁代码块, 作用范围是方法上
  • @Log : 根据不同的注解生成不同类型的log对象,但是实例名称都是log,有六种可选实现类
  • @NoArgsConstructor:注解在类上; 会生成一个返回类对象的静态工厂方法。
  • @RequiredArgsConstructor:注解在类上;为类提供一个部分参的构造方法(使用类中所有带有@NonNull注解的或者带有final修饰的成员变量生成对应的构造方法)
  • @AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
  • @Cleanup:用于确保已分配的资源被释放,如IO的连接关闭
  • @SneakyThrows:抛异常
  • @Accessors: 用于配置getter和setter方法的生成结果

3.1、val

用在局部变量前面,相当于将变量声明为final

public static void main(String[] args) {
        /**
         * str1 和 str2的两种定义方法都可以
         */
        val str1="abc";
        final String str2="abc";
    }

3.2、@Data

注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法,相当于同时加上以下注解@Setter @Getter,@ToString,@EqualsAndHashCode

@Data
public class Book {

    private  String isbn;
    private String book_name;
    private String price;
}

效果同@Value

3.3、@Value

@Value
@AllArgsConstructor
public class Book {

    private  String isbn;
}

相当于

public class Book {

    private final String isbn;
  
  	public String getIsbn() {
        return isbn;
    }
}

调用、

 Book book = new Book("1");

3.4、@Getter@Setter

注解在类和属性上;为属性提供 setting、getting 方法

public class Book {
    
    @Setter@Getter
    private  String isbn;
}

3.5、@Getter(lazy=true)

如果 Bean 的一个字段的初始化是代价比较高的操作,比如加载大量的数据;同时这个字段并不是必定使用的。那么使用懒加载机制,可以保证节省资源。

懒加载机制,是对象初始化时,该字段并不会真正的初始化,而是第一次访问该字段时才进行初始化字段的操作。

public class GetterLazyExample {
    @Getter(lazy = true)
    private final double[] cached = expensive();
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

// 相当于如下所示: 

import java.util.concurrent.atomic.AtomicReference;
public class GetterLazyExample {
    private final AtomicReference<java.lang.Object> cached = new AtomicReference<>();
    public double[] getCached() {
        java.lang.Object value = this.cached.get();
        if (value == null) {
            synchronized (this.cached) {
                value = this.cached.get();
                if (value == null) {
                    final double[] actualValue = expensive();
                    value = actualValue == null ? this.cached : actualValue;
                    this.cached.set(value);
                }
            }
        }
        return (double[]) (value == this.cached ? null : value);
    }
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

3.6、@ToString

生成 toString 方法,默认情况下,会输出类名、所有属性,属性按照顺序输出,以逗号分割。但需要注意的是:@ToString有多个属性可以进一步设置:

  • callSuper 是否输出父类的toString方法,默认为false
  • includeFieldNames 是否包含字段名称,默认为true
  • exclude 排除生成tostring的字段
@ToString(callSuper = true,exclude ={"name"})
public class Person {
    private String name;
    private String address;
}

3.7、@EqualsAndHashCode

用在类上,自动生成 equals 方法和 hashCode 方法

参数exclude排除一些属性 ; 参数of指定仅使用哪些属性 ; 默认仅使用该类中定义的属性且不调用父类的方法 (即 callSuper=false)。

//父类
public class Person {
    private String name;
    private String sex;

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
}
@EqualsAndHashCode(exclude = {"className"},callSuper = false)
public class Student extends Person{
    @Getter@Setter
    private int age;
    @Getter@Setter
    private String className;

    public Student(String name,String sex,int age,String className) {
        super(name,sex);
        this.age = age;
        this.className = className;
    }
}
Student s1 = new Student("hresh","man",22,"Lv3");
Student s2 = new Student("hresh","woman",22,"Lv5");
System.out.println(s1.equals(s2));//true

解析: 子类实现@EqualsAndHashCode(callSuper = false) ,不调用父类的属性,那么子类属性里面的相同的话,那 hashcode 的值就相同,再加上排除对 className 属性的比对,所以代码里面的2个对象的 equals 方法的返回值是 true 。

3.8、@NonNull

该注解快速判断是否为空,如果为空,则抛出 java.lang.NullPointerException

public class Person {

    private String name;

    @Setter@Getter@NonNull
    private List<Person> member;
}

等价于:

@NonNull
private List<Person> members;

public Family(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}

@NonNull
public List<Person> getMembers() {
    return members;
}

public void setMembers(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}

3.8、@Synchronized

该注解自动添加到同步机制,有趣的是,生成的代码并不是直接锁方法,而是锁代码块, 作用范围是方法上。

private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");

@Synchronized
public String synchronizedFormat(Date date) {
    return format.format(date);
}

等价于:

private final java.lang.Object $lock = new java.lang.Object[0];
private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");

public String synchronizedFormat(Date date) {
    synchronized ($lock) {
        return format.format(date);
    }
}

3.9、@NoArgsConstructor

注解在类上;为类提供一个无参的构造方法

@Data
@NoArgsConstructor(staticName = "init")
public class Student {
    private long id = new Long(0);
    private String name = " ";
    private String className = " ";
}

等价于:

@Data
//@NoArgsConstructor(staticName = "init")
public class Student {
    private long id = new Long(0);
    private String name = " ";
    private String className = " ";

    public static Student init(){
        return new Student();
    }
}

3.10、@AllArgsConstructor

注解在类上,为类提供一个全参的构造方法

@Data
@AllArgsConstructor
public class Student {
    private long id = new Long(0);
    private String name = " ";
    private String className = " ";
}

相当于:

@Data
public class Student {
    private long id = new Long(0);
    private String name = " ";
    private String className = " ";

    public Student(long id, String name, String className) {
        this.id = id;
        this.name = name;
        this.className = className;
    }
}

3.11、@RequiredArgsConstructor

注解在类上;为类提供一个部分参的构造方法(使用类中所有带有@NonNull注解的或者带有final修饰的成员变量生成对应的构造方法)

@Data
@RequiredArgsConstructor
public class Student {
    @NonNull
    private long id ;
    @NonNull
    private String name ;
    private String className;

}

实际调用:

Student student = new Student(101,"hresh");
System.out.println(student);

3.12、@Cleanup

注释可用于确保已分配的资源被释放,如 IO 的连接关闭。

public void testCleanUp() {
    try {
        @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(new byte[] {'Y','e','s'});
        System.out.println(baos.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

等价于:

public void testCleanUp() {
    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(new byte[]{'Y', 'e', 's'});
            System.out.println(baos.toString());
        } finally {
            baos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3.13、@Log

@CommonsLog 
Creates log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Log Creates log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j Creates log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2 Creates log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j Creates log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

@XSlf4j Creates log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

已slf4j 日志对象为例。

注解在类上;为类提供一个 属性名为log 的 slf4j 日志对象

@Slf4j
public class StudentTest {

    public static void main(String[] args) {
        log.info("Here is some INFO");
    }
}

等价于:

 public class StudentTest {

    public static Logger log = LoggerFactory.getLogger(StudentTest.class);

    public static void main(String[] args) {
        log.info("Here is some INFO");
    }
}

2.14、@Accessors

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

1、 fluent

fluent 的中文含义是流畅的,设置为true 则 生成的get/set方法则没有 set/get 前缀,默认为 false 。

@Data
@Accessors(fluent = true)
public class Student {
    private long id = new Long(0);
    private String name = " ";
    private String className = " ";

}

实际调用

public class StudentTest {

    public static void main(String[] args) {
        Student student = new Student();
        student.name("hresh");//相当于SetName()
        student.className("Lv5");
        System.out.println(student);
        System.out.println(student.name());//相当于getName()
    }
}

2、 chain

chain 的中文含义是链式的,为一个布尔值, 如果为 true 生成的 set 方法返回 this,为 false 生成的 set 方法是 void 类型。 默认为 false,除非当 fluent 为 true时,chain 默认则为 true 。

@Setter
@Getter
@Accessors(chain = true)
public class User {
    private String id;
    private String name;
    private Integer age;
}

public static void main(String[] args) {
    //使用@Accessors(chain = true)
    User userChain = new User();
    userChain.setId("1").setName("chain").setAge(1);
}

3、 prefix

prefix 为一系列 string 类型,可以指定前缀,生成 get/set 方法时会去掉指定的前缀 。

@Data
@Accessors(prefix = "n")
public class Student {
//    private long id = new Long(0);
    private String nAme = " ";
    private String name = " ";
    private String className = " ";
    private int nId  = new Integer(0);
}

实际调用:

public class StudentTest {

    public static void main(String[] args) {
        Student student = new Student();

        student.setId(101);
        System.out.println(student.getId());
        student.setAme("hresh");
        student.setName("hresh");
        System.out.println(student);
    }
}

需要注意的是,此时类中的属性命名存在这样的规则,指定前缀+大写字符,像上述代码中如果属性为 name 而非 nAme,则不成立。

2.15、@SneakyThrows

自动抛受检异常,而无需显式在方法上使用 throws 语句

@SneakyThrows
public void read(){
    InputStream inputStream = new FileInputStream("");
}
//相当于
public void read() throws FileNotFoundException {
    InputStream inputStream = new FileInputStream("");
}

2.16、@Builder

用在类、构造器、方法上,为你提供复杂的 builder APIs

@Builder
@Data
public class Student {
    private String name ;
    private int age;
}

实际调用:

public class StudentTest {

    public static void main(String[] args) {
        Student student = Student.builder().name("hresh").age(22).build();
    }
}

等价于:

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static Builder builder(){
        return new Builder();
    }
    public static class Builder{
        private String name;
        private int age;
        public Builder name(String name){
            this.name = name;
            return this;
        }

        public Builder age(int age){
            this.age = age;
            return this;
        }

        public Student build(){
            Student student = new Student();
            student.setAge(age);
            student.setName(name);
            return student;
        }
    }
}

2.17、@UtilityClass:工具类注解

@UtilityClass
public class Utility {

    public String getName() {
        return "name";
    }
}

public static void main(String[] args) {
    // Utility utility = new Utility(); 构造函数为私有的,
    System.out.println(Utility.getName());

}
原文地址:https://www.cnblogs.com/jdy1022/p/13969967.html