Lombok之使用详解

简介: Lombok之使用详解

前言


在 Java 中,封装是一个非常好的机制,最常见的封装莫过于 get,set 方法了,无论是 Intellij idea 还是 Eclipse,都提供了快速生成 get,set 方法的快捷键,使用起来很是方便,其实,我们还有更方便的办法,那就是-Lombok:非常强大的 POJO 注解器。


Lombok 是什么?


lombok 提供了简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 java 代码。特别是相对于 POJO。


如何安装 Lombok?


1、通过 IntelliJ 的插件中心安装

image.png

2、 Install Plugin

image.png


3、 最后需要注意的是,在使用 lombok 注解的时候记得要导入 lombok.jar 包到工程,如果使用的是 Maven Project,要在 pom.xml 中添加依赖。


<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.8</version>
</dependency>
复制代码


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方法的生成结果


val


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

public static void main(String[] args) {
    val sets = new HashSet<String>();
    //=>相当于如下
    final Set<String> sets2 = new HashSet<>();
}
复制代码


@Data


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


@Data
public class Person {
    private String name;
    private String address;
    private String city;
    private String state;
    private String zip;
    private Date brithday;
}
复制代码


效果同下:


@Value


@Value
@AllArgsConstructor
public class Student {
    private String name ;
    private int age;
    //相当于
    private final int age;
    public int getAge(){
        return this.age;
    }
}
复制代码


实际调用:


Student student = new Student("hresh",22);//没有set方法
System.out.println(student);
System.out.println(student.getName());
复制代码


@Getter@Setter


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

public class Person {
    @Getter@Setter
    private String name;
}
复制代码

等价于:

public String getName() {
        return name;
    }
public void setName(String name) {
        this.name = name;
}
复制代码


@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;
    }
}
复制代码


@ToString


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

  • callSuper 是否输出父类的toString方法,默认为false
  • includeFieldNames 是否包含字段名称,默认为true
  • exclude 排除生成tostring的字段


@ToString(callSuper = true,exclude ={"name"})
public class Person {
    private String name;
    private String address;
}
复制代码


等价于:


public String toString() {
 return "Person{" +
                "address='" + address + '\'' +
    '}';
}
复制代码


@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 。


@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;
}
复制代码


@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);
    }
}
复制代码


@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();
    }
}
复制代码

调用时:

public class StudentTest {
    public static void main(String[] args) {
//        Student student = new Student();//编译时报错
        Student student = Student.init();
        student.setName("hresh");
        student.setClassName("Lv5");
        System.out.println(student);
    }
}
复制代码


@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;
    }
}
复制代码


@RequiredArgsConstructor


@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);
复制代码


@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();
    }
}
复制代码


@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");
    }
}
复制代码


@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 。


@Data
@Accessors(chain = 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 student1 = student.setClassName("Lv5");
        System.out.println(student);
        System.out.println(student1);
    }
}
复制代码


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,则不成立。


@SneakyThrows


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

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


@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;
        }
    }
}



目录
相关文章
|
3月前
|
Java
lombok的使用
本文介绍了Lombok库的基本使用方法和常用注解,通过示例代码展示了如何使用Lombok简化Java对象的创建、属性访问、日志记录等编码工作,使代码更加简洁。
lombok的使用
|
3月前
|
IDE Java 编译器
lombok编译遇到“找不到符号的问题”
【9月更文挑战第18天】当使用 Lombok 遇到 “找不到符号” 的问题时,可能是由于 Lombok 未正确安装、编译器不支持、IDE 配置不当或项目构建工具配置错误。解决方法包括确认 Lombok 安装、编译器支持,配置 IDE 和检查构建工具配置。通过这些步骤通常可解决问题,若问题仍存在,建议检查项目配置和依赖,或查看日志获取更多信息。
1582 2
|
4月前
|
IDE Java 开发工具
Java 开发神器 Lombok:告别冗余,拥抱优雅!
Java 开发神器 Lombok:告别冗余,拥抱优雅!
80 0
|
6月前
|
安全 IDE Java
使用MapStruct和Lombok简化代码
使用MapStruct和Lombok简化代码
193 2
|
6月前
|
IDE Java 程序员
Lombok使用方法和总结
Lombok使用方法和总结
|
5月前
|
Java
@SneakyThrows 是 Lombok 库中的一个注解
`@SneakyThrows` 是 Lombok 库中的一个注解,它可以让你在方法签名中省略异常声明,而不需要显式地使用 try-catch 块来处理这些异常。当你使用 `@SneakyThrows` 注解时,Lombok 会自动生成相应的 try-catch 代码,将异常封装成运行时异常(通常是 `RuntimeException` 或其子类)。 这个注解在某些情况下可以简化代码,但请注意,它可能会隐藏潜在的问题,因为异常被转换成了运行时异常,这可能导致调用者无法正确处理这些异常。 下面是一个使用 `@SneakyThrows` 的示例: ```java import lombok.S
396 0
|
6月前
|
Java Maven Python
技术笔记:Lombok介绍、使用方法和总结
技术笔记:Lombok介绍、使用方法和总结
80 0
|
7月前
|
IDE Java 数据库连接
Lombok注解大全
这些是Lombok中的一些常见注解,它们可以显著减少Java代码中的冗余代码,提高代码的可读性和可维护性。不过,在使用Lombok之前,请确保你的开发环境已经配置好支持Lombok,通常需要安装相应的插件或进行设置以使IDE(如Eclipse、IntelliJ IDEA)能够正确解析Lombok注解。
57 4
|
7月前
|
IDE Java 数据库连接
Lombok注解大全
这些是Lombok中的一些常见注解,它们可以显著减少Java代码中的冗余代码,提高代码的可读性和可维护性。不过,在使用Lombok之前,请确保你的开发环境已经配置好支持Lombok,通常需要安装相应的插件或进行设置以使IDE(如Eclipse、IntelliJ IDEA)能够正确解析Lombok注解。
104 2
|
7月前
|
IDE Java 开发工具
Lombok 详解:简化 Java 开发的神奇工具
Lombok 是一款 Java 工具,通过注解自动处理如 getter/setter、toString、equals 和 hashCode 等常见代码,减少样板代码。安装 Lombok 需要在 IDE(如 IntelliJ IDEA)中添加插件,并在 Maven 或 Gradle 项目中配置依赖。常用注解包括 @Getter/@Setter 生成访问器,@ToString 生成对象描述,@EqualsAndHashCode 生成比较方法,@NoArgsConstructor/@AllArgsConstructor 生成构造器,@Data 综合应用这些注解。
420 9