没有理想的人不伤心

Java - Lombok

2025/08/28
2
0

image.png

Lombok 是一款 Java 开发工具库,通过注解的方式简化代码编写,消除冗余的 getter/setter、构造方法、toString 等模板代码,让代码更简洁、易维护。其核心原理是在编译期通过注解处理器自动生成这些代码,无需手动编写。

主要用于简化代码编写,设计内容:getter/setter、构造方法、toString、equals 等模板代码,以及日志

一、核心优势

  • 减少模板代码:省去手动编写 getter/setter、构造方法等重复工作。
  • 提高开发效率:专注业务逻辑,减少代码量。
  • 降低维护成本:当类属性变更时,无需手动修改相关方法。

使用和不使用 lombok 最直观的对比:
使用 Lombok 可以不用写 getter/setter、构造方法、toString、equals 等模板代码
不使用 lombok:

public class User implements Serializable {

    private static final long serialVersionUID = -8054600833969507380L;

    private Integer id;

    private String username;

    private Integer age;

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return"User{" +
                "id=" + id +
                ",username='" + username + '\'' +
                ",age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if(this == o) {
            return true;
        }
        if(o == null || getClass() != o.getClass()) {
            return false;
        }
        User user = (User)o;
        return Objects.equals(id,user.id) &&
                Objects.equals(username,user.username) &&
                Objects.equals(age,user.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id,username,age);
    }

}

使用 Lombok:

@Data
public class User implements Serializable {

    private static final long serialVersionUID = -8054600833969507380L;

    private Integer id;

    private String username;

    private Integer age;

}

二、常用注解及用法

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

1. @Data (最常用)

作用:组合注解,自动生成 getter、setter、toString、equals、hashCode 方法(不包含无参/有参构造方法)。
适用场景:绝大多数 POJO 类(实体类)。

import lombok.Data;

@Data
public class User {
    private Long id;
    private String username;
    private Integer age;
    // 编译后自动生成:
    // getter/setter 方法
    // toString()、equals()、hashCode() 方法
}

2. @Getter / @Setter

作用:为类或属性单独生成 getter/setter 方法。
适用场景:只需部分属性生成 getter/setter 时。

import lombok.Getter;
import lombok.Setter;

public class User {
    @Getter @Setter  // 为 id 生成 getter/setter
    private Long id;
    
    private String username;  // 无注解,不生成
    
    @Getter  // 只为 age 生成 getter
    private Integer age;
}

3. @ToString

作用:生成 toString() 方法,默认包含所有非静态属性。
扩展exclude 排除指定属性,of 只包含指定属性。

import lombok.ToString;

@ToString(exclude = "password")  // 排除 password 属性
public class User {
    private Long id;
    private String username;
    private String password;  // 不包含在 toString 中
}

4. @NoArgsConstructor / @AllArgsConstructor

作用

  • @NoArgsConstructor :生成无参构造方法。
  • @AllArgsConstructor :生成包含所有属性的有参构造方法(顺序与属性定义一致)。

注意:如果类中已有自定义构造方法,Lombok 不会覆盖。

import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    // 编译后生成:
    // 无参构造:public User() {}
    // 全参构造:public User(Long id,String username) { ... }
}

5. @RequiredArgsConstructor

作用:生成包含“必需属性”的构造方法(必需属性指被 final 修饰或被 @NonNull 标记的属性)。
适用场景:依赖注入(如 Spring 的构造器注入)。

import lombok.RequiredArgsConstructor;
import lombok.NonNull;

@RequiredArgsConstructor
public class UserService {
    private final UserDao userDao;  // final 修饰,必需属性
    @NonNull private String appName;  // @NonNull 标记,必需属性
    private Integer version;  // 非必需,不包含在构造方法中
    
    // 编译后生成:
    // public UserService(UserDao userDao,String appName) { ... }
}

6. @Slf4j (日志相关)

作用:自动生成日志对象( private static final Logger log = LoggerFactory.getLogger(当前类.class);),支持主流日志框架(如 SLF4J)。
适用场景:需要打印日志的类(Service、Controller 等)。

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class UserService {
    public void queryUser() {
        log.info("查询用户信息");  // 直接使用 log 对象
        log.error("查询失败",new Exception("错误"));
    }
}

7. @NonNull

作用:为方法参数或属性添加非空校验,若传入 null 则抛出 NullPointerException

import lombok.NonNull;

public class User {
    private String username;
    
    public void setUsername(@NonNull String username) {
        this.username = username;  // 若传入 null,直接抛异常
    }
}

8. @Builder

作用:为类生成建造者模式代码,支持链式调用创建对象。
适用场景:属性较多的类,创建对象时代码更清晰。

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class User {
    private Long id;
    private String username;
    private Integer age;
}

// 使用方式:
User user = User.builder()
    .id(1L)
    .username("zhangsan")
    .age(20)
    .build();  // 链式调用创建对象

三、注意事项

  1. 注解冲突:避免同时使用 Lombok 注解和手动编写的同名方法(如手动写了 toString(),@ToString 会失效)。
  2. 继承问题@ToString @EqualsAndHashCode 默认不包含父类属性,如需包含可添加 callSuper = true(如 @ToString(callSuper = true))。
  3. IDE 支持:虽然无需手动安装 Lombok,但 IDE 需启用注解处理器(IntelliJ IDEA 通常默认支持,若报错可在设置中开启)。

四、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 点原因:

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

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

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

javac 对源代码进行分析,生成了一棵抽象语法树(AST)
运行过程中调用实现了“JSR 269 API”的 Lombok 程序
此时 Lombok 就对第一步骤得到的 AST 进行处理,找到@Data 注解所在类对应的语法树(AST),然后修改该语法树(AST),增加 getter 和 setter 方法定义的相应树节点
javac 使用修改后的抽象语法树(AST)生成字节码文件,即给 class 增加新的节点(代码块)
通过读 Lombok 源码,发现对应注解的实现都在 HandleXXX 中,比如@Getter 注解的实现在 HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如 Google Auto、Dagger 等等。

五、优缺点

优点:

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

缺点:

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