Lombok

537 阅读6分钟

1、概述

1.1 什么是 Lombok?

Lombok:是一个 Java 库,它可以通过注解的方式自动生成常用的模板代码,从而减少手动编写样板代码的需要。

Lombok 的特点:

  1. 减少模板代码:Lombok 可以通过注解自动生成常用的方法,如 getter/setter、构造函数、toStringequalshashCode 方法,从而减少了编写样板代码的需要。

  2. 编译时处理:Lombok 使用注解处理器在编译时生成代码,这意味着生成的代码是实际的 Java 字节码,而不是运行时代理或字节码操纵。

  3. 非侵入性:Lombok 注解不会对现有的代码库造成侵入性影响,你可以在任何现有的 Java 项目中引入 Lombok。

1.2 Lombok 的引入

Maven:

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

Gradle:

compileOnly 'org.projectlombok:lombok:x.x.x'
annotationProcessor 'org.projectlombok:lombok:x.x.x'

注意:

  1. 在 IDEA 中使用,需要安装 Lombok 插件。
  2. 在 Spring Boot 2.1.x 后,已经在 spring-boot-dependencies 中内置,引入时无需指定版本。

1.3 Lombok 的原理

在 IDEA 中,如果不安装 Lombok 插件,使用 Lombok,在编译期是无法通过的。而安装 Lombok 插件后,查看 .class 文件,会发现增强的代码已经存在了,而 .java 文件中是无法看到的。

Lombok 通过利用 Java 编译器的注解处理 API 在编译时生成额外的代码,从而达到减少模板代码的目的。当编译器遇到带有 Lombok 注解的代码时,Lombok 会介入编译过程,读取注解,并为标注的代码生成相应的实现。这个过程对开发者是透明的,开发者只需要在代码中使用 Lombok 提供的注解,然后编译器在编译 Java 文件时会处理这些注解。

2、基础注解

2.1 Setter

  • 作用:为类的私有字段生成对应的 setter() 方法。
  • 位置:类级别、字段级别。
  • 示例:
// 1. 使用后 Lombok
@Setter
public class Student {
    private String name;
}

// 2. 不使用 Lombok
public class Student {
    private String name;

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

2.2 Getter

  • 作用:为类的私有字段生成对应的 getter()方法。
  • 位置:类级别、字段级别。
  • 示例:
// 1. 使用后 Lombok
@Getter
public class Student {
    private String name;
}

// 2. 不使用 Lombok
public class Student {
    private String name;

    public String getName() {
        return this.name;
    }
}

2.3 ToString

  • 作用:为类生成 toString() 方法,包含所有字段。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@ToString
public class Student {
    private String name;
}

// 2. 不使用 Lombok
public class Student {
    private String name;

    @Override
    public String toString() {
        return ...;
    }
}

2.4 NoArgsConstructor

  • 作用:为类生成无参构造函数。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@NoArgsConstructor
public class Student {
    private String name;
}

// 2. 不使用 Lombok
public class Student {
    private String name;

    public Student() {
        this.name = "";
    }
}

2.5 AllArgsConstructor

  • 作用:为类生成包含所有字段的构造函数。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@AllArgsConstructor
public class Student {
    private String name;
}

// 2. 不使用 Lombok
public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }
}

2.6 RequiredArgsConstructor

  • 作用:为类生成包含所有 final 字段的构造函数。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@AllArgsConstructor
public class Student {
    private final String name;
    private int age;
}

// 2. 不使用 Lombok
public class Student {
    private final String name;
    private int age;

    public Student(String name) {
        this.name = name;
    }
}

2.7 EqualsAndHashCode

  • 作用:为类生成 equals()hashCode() 方法。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@EqualsAndHashCode
public class Student {
    private final String name;
    private int age;
}

// 2. 不使用 Lombok
public class Student {
    private final String name;
    private int age;

    public boolean equals(Student student) {
        // ...
    }

    public 
}

2.8 Data

  • 作用:是一个复合注解,相当于 @ToString + @EqualsAndHashCode + @Getter + @Setter
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@Data
public class Student {
    private String name;
    private int age;
}

// 2. 不使用 Lombok
public class Student {
    private String name;
    private int age;

    public Student() {
        this.name = "";
        this.age = 0;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

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

    public String getAge() {
        return this.age;
    }

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

    @Override
    public boolean equals(Object o) {
        // ...
    }

    @Override
    public int hashCode() {
        // ...
    }
}

2.9 Value

  • 作用:用于生成不可变对象,所有字段默认为 final,。它是一个复合注解,相当于 @ToString + @EqualsAndHashCode + @Getter + @RequiredArgsConstructor。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@Value
public class Student {
    private final String name;
    private final int age;
}

// 2. 不使用 Lombok
public class Student {
    private final String name;
    private final int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    @Override
    public boolean equals(Object o) {
        // ...
    }

    @Override
    public int hashCode() {
        // ...
    }

    @Override
    public String toString() {
        // ...
    }
}

2.10 Builder

  • 作用:为类生成建造者模式的代码,方便复杂对象的构建。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@Builder
public class Student {
    private String name;
    private int age;
}

// 2. 不使用 Lombok
public class Student {
    private String name;
    private int age;

    // 私有构造函数
    private Student() {}

    public static class Builder {
        private String name;
        private int age;

        public StudentBuilder name(String name) {
            this.name = name;
            return this;
        }

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

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

3、其他注解

3.1 Slf4j

  • 作用:为类生成一个日志对象,支持 SLF4J 日志框架。
  • 位置:类级别。
  • 示例:
// 1. 使用后 Lombok
@Slf4j
public class Student {
    private String name;
    private int age;
}

// 2. 不使用 Lombok
public class Student {
    // 创建一个 Logger 实例
    private static final Logger log = LoggerFactory.getLogger(MyClass.class);

    private String name;
    private int age;
}

3.2 SneakyThrows

  • 作用:允许方法抛出一个或多个检查异常,而不需要在方法签名中声明。
  • 位置:方法级别。
  • 示例:
// 1. 使用后 Lombok
public class Student {
    private String name;
    private int age;

    @SneakyThrows
    public String getName() {
        // 抛出 Exception
        return name;
    }

    @SneakyThrows
    public int getAge() {
        // 抛出 Exception
        return age;
    }
}

// 2. 不使用 Lombok
public class Student {
    private String name;
    private int age;

    public String getName() {
        try {
            // 抛出 Exception
            return name;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public int getAge() {
        try {
            // 抛出 Exception
            return age;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3.3 Synchronized

  • 作用:为方法生成同步代码块,确保线程安全。
  • 位置:方法级别。
  • 示例:
// 1. 使用后 Lombok
public class Counter {
    private int count = 0;

    @Synchronized
    public void increment() {
        count++;
    }

    @Synchronized
    public int getCount() {
        return count;
    }
}

// 2. 不使用 Lombok
public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

3.4 UtilityClass

  • 作用:标记工具类,防止实例化和继承。
  • 位置:类级别。
  • 示例:
@UtilityClass
public class StringUtils {
    /** * 将字符串转换为大写,如果字符串为 null,则返回 null。 */
    public static String toUpperCase(String str) {
        return str == null ? null : str.toUpperCase();
    }

    /** * 检查字符串是否为 null 或空。 */
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
}

3.5 NotNull

  • 作用:确保方法参数不为 null,如果为 null 则抛出 NullPointerException 异常。
  • 位置:方法参数级别。
  • 示例:
public void registerUser(@NonNull String username) {
    // ...
}

3.6 Nullable

  • 作用:标记字段、方法参数或返回值可以为 null。
  • 位置:字段级别、方法参数级别、返回值级别。
  • 示例:
public class UserService {
    @Nullable
    private String optionalField;

    public @Nullable String findUserById(int id) {
        // ...
        return null;
    }

    public void processUser(@Nullable String username) {
        // ...
    }
}

3.7 Cleanup

  • 作用:自动释放资源,类似于 Java 7 引入的 try-with-resources 语句。当标记的资源不再需要时,Lombok 会自动调用其 close 方法。
  • 位置:字段级别、方法参数级别、返回值级别。
  • 示例:
@Cleanup Reader reader = new StringReader("xxx");
int data = reader.read();
while (data != -1) {
    // ...
}