2、Lombok核心注解详解:@Getter、@Setter、@Data 等基础注解全面解析

【投稿赢 iPhone 17】「我的第一个开源项目」故事征集:用代码换C位出道! 10w+人浏览 1.8k人参与

学习目标:掌握 Lombok 最常用的 8 个核心注解,理解它们如何简化 POJO 编写,知道每个注解的生成效果、参数配置和适用场景。


1. 为什么需要这些注解?

在 Java 开发中,数据类(POJO/DTO/VO/Entity)通常需要以下方法:

  • Getter/Setter:访问和修改字段
  • toString():调试和日志输出
  • equals() / hashCode():集合操作、去重、缓存键
  • 构造器:对象初始化
  • 日志对象:记录运行信息

手动编写这些方法不仅繁琐,还容易出错。Lombok 通过注解一键生成,让我们专注业务字段定义。


2. POJO 简化“四件套”

2.1 @Getter 和 @Setter

基本用法
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Product {
    private Long id;
    private String name;
    private Double price;
}

生成效果

  • 为每个非静态字段生成 public 的 getter 和 setter 方法
  • boolean 字段的 getter 以 is 开头(如 isActive()
// 实际生成的代码(反编译后)
public Long getId() { return this.id; }
public void setId(Long id) { this.id = id; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
// ... 其他字段类似
精细控制

你可以控制访问级别和排除字段:

@Getter(AccessLevel.PROTECTED)  // getter 为 protected
@Setter(AccessLevel.NONE)       // 禁用所有 setter
public class User {
    private String username;
    
    @Setter(AccessLevel.PRIVATE) // 单独为字段设置
    private String password;
    
    @Getter(AccessLevel.NONE)    // 不生成 getter
    private String secretKey;
}

AccessLevel 可选值PUBLIC(默认)、PROTECTEDPACKAGEPRIVATENONE

使用场景
  • ✅ 大多数 POJO/DTO/VO/Entity 类
  • ❌ 不适用于需要自定义逻辑的 setter(如参数校验)

2.2 @ToString

基本用法
@ToString
public class Order {
    private Long id;
    private String customerName;
    private Double amount;
}

生成效果

@Override
public String toString() {
    return "Order(id=" + this.id + 
           ", customerName=" + this.customerName + 
           ", amount=" + this.amount + ")";
}
常用参数
@ToString(
    includeFieldNames = true,   // 包含字段名(默认 true)
    callSuper = false,          // 是否调用父类 toString()(默认 false)
    exclude = {"password"},     // 排除敏感字段
    of = {"id", "name"}         // 只包含指定字段(优先级高于 exclude)
)
public class User {
    private Long id;
    private String name;
    private String password;    // 不会出现在 toString 中
}

💡 安全提示:永远不要在 toString() 中输出密码、密钥等敏感信息!

使用场景
  • ✅ 所有需要日志输出或调试的类
  • ✅ API 响应对象(便于排查问题)

2.3 @EqualsAndHashCode

基本用法
@EqualsAndHashCode
public class Book {
    private String isbn;
    private String title;
}

生成效果

  • 基于所有非静态、非 transient 字段生成 equals()hashCode()
  • 遵循 Java 规范:相等对象必须有相同 hashCode
@Override
public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof Book)) return false;
    Book other = (Book) o;
    if (!other.canEqual(this)) return false;
    final Object this$isbn = this.isbn;
    final Object other$isbn = other.isbn;
    if (this$isbn == null ? other$isbn != null : !this$isbn.equals(other$isbn)) return false;
    // ... 其他字段比较
    return true;
}

@Override
public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    result = result * PRIME + (this.isbn == null ? 43 : this.isbn.hashCode());
    // ... 其他字段
    return result;
}
重要参数
@EqualsAndHashCode(
    callSuper = false,          // 是否包含父类字段(默认 false)
    exclude = {"createTime"},   // 排除字段
    of = {"id"}                 // 只基于 id 判断相等性
)
public class Article {
    private Long id;
    private String title;
    private LocalDateTime createTime; // 不参与 equals/hashCode
}

⚠️ 继承警告:如果类有子类,建议设置 callSuper = true,否则可能违反 equals 对称性。

使用场景
  • ✅ 存储在 HashSetHashMap 中的对象
  • ✅ 需要去重的业务场景
  • ❌ 不适用于包含循环引用的对象(可能导致 StackOverflow)

3. 组合注解:事半功倍

3.1 @Data(最常用!)

@Data 是 Lombok 的“瑞士军刀”,组合了多个注解

// @Data 等价于以下注解的组合:
@Getter
@Setter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
使用示例
@Data
public class Student {
    private Long id;
    private String name;
    private Integer age;
}

自动生成

  • 所有字段的 getter/setter
  • toString() 方法
  • equals() 和 hashCode()
  • @RequiredArgsConstructor:为所有 final 字段和 @NonNull 字段生成构造器
注意事项
  • 不会生成无参构造器!如果需要,需额外添加 @NoArgsConstructor
  • 谨慎用于 JPA Entity:某些框架要求无参构造器
使用场景
  • ✅ DTO(数据传输对象)
  • ✅ VO(视图对象)
  • ✅ 简单的配置类
  • ❌ 复杂的业务实体(可能需要自定义 equals/hashCode 逻辑)

3.2 @Value(不可变对象)

@Value 用于创建不可变类(Immutable Class):

@Value
public class Point {
    private final int x;
    private final int y;
}

生成效果

  • 所有字段自动变为 private final
  • 只生成 getter(无 setter)
  • 生成全参构造器
  • 生成 toString、equals、hashCode

等价于:

// 手动编写需要这么多代码!
public final class Point {
    private final int x;
    private final int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public int getX() { return x; }
    public int getY() { return y; }
    
    @Override
    public boolean equals(Object o) { /* ... */ }
    
    @Override
    public int hashCode() { /* ... */ }
    
    @Override
    public String toString() { /* ... */ }
}
使用场景
  • ✅ 配置项(如数据库连接信息)
  • ✅ 函数式编程中的值对象
  • ✅ 多线程安全的数据载体

4. 构造器注解:灵活初始化

4.1 @NoArgsConstructor

生成无参构造器

@NoArgsConstructor
public class User {
    private String name;
    private Integer age;
}

// 生成:public User() {}

重要:JPA、Jackson 等框架通常要求实体类有无参构造器。


4.2 @AllArgsConstructor

生成全参构造器(包含所有字段):

@AllArgsConstructor
public class Product {
    private Long id;
    private String name;
    private Double price;
}

// 生成:public Product(Long id, String name, Double price) { ... }

4.3 @RequiredArgsConstructor

生成必需字段构造器

  • 所有 final 字段
  • 所有标记 @NonNull 的字段
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository; // final 字段
    
    @NonNull
    private String defaultRole; // @NonNull 字段
}

// 生成:public UserService(UserRepository userRepository, String defaultRole) { ... }

💡 Spring 推荐用法:配合 @RequiredArgsConstructor 实现构造器注入,替代 @Autowired


4.4 构造器组合使用

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
    private Long id;
    private String customerName;
    private Double amount;
}

这样既支持无参构造(框架需要),也支持全参构造(测试或 Builder 模式)。


5. 日志注解:告别手动声明

5.1 @Slf4j(最常用)

自动生成 SLF4J 日志实例:

@Slf4j
public class OrderService {
    public void processOrder(Order order) {
        log.info("Processing order: {}", order.getId());
        log.debug("Order details: {}", order);
    }
}

// 等价于手动编写:
// private static final Logger log = LoggerFactory.getLogger(OrderService.class);

5.2 其他日志框架支持

注解对应框架
@Logjava.util.logging
@Log4jLog4j 1.x
@Log4j2Log4j 2.x
@CommonsLogApache Commons Logging
@JBossLogJBoss Logging

推荐:使用 @Slf4j,它是日志门面,便于切换底层实现。


6. 注解使用对比表

注解生成内容典型场景注意事项
@Getter/@Settergetter/setter 方法通用 POJO可控制访问级别
@ToStringtoString() 方法调试、日志排除敏感字段
@EqualsAndHashCodeequals()/hashCode()集合操作继承时注意 callSuper
@Data以上全部 + RequiredArgsConstructorDTO、VO不生成无参构造器
@Value不可变类全套方法配置、值对象字段自动 final
@NoArgsConstructor无参构造器JPA Entity、Jackson框架集成必需
@AllArgsConstructor全参构造器测试、Builder字段顺序敏感
@Slf4j日志实例所有服务类推荐 SLF4J

7. 实战示例:完整用户类

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.ToString;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

// 组合使用:DTO 场景
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude = "password") // 安全:不打印密码
@EqualsAndHashCode(exclude = "lastLoginTime") // 登录时间不影响用户相等性
@Slf4j
public class UserDTO {
    private Long id;
    private String username;
    private String password; // 敏感字段
    private String email;
    private LocalDateTime lastLoginTime;
    
    public static void main(String[] args) {
        UserDTO user = new UserDTO(1L, "john", "secret", "john@example.com", null);
        log.info("Created user: {}", user); // 不会泄露密码
    }
}

8. 小结

你已掌握

  • 四件套注解@Getter/@Setter/@ToString/@EqualsAndHashCode 的精细控制
  • 组合注解@Data(万能)和 @Value(不可变)的适用场景
  • 构造器注解:三种构造器的生成规则和组合使用
  • 日志注解@Slf4j 快速集成日志

➡️ 下一步:进入 03-Lombok进阶功能实战,学习 @Builder@SneakyThrows 等高级功能!

💡 最佳实践提醒

  • 优先使用 @Data + @NoArgsConstructor 组合
  • 敏感字段务必在 @ToString 中排除
  • Entity 类慎用 @Data,建议手动控制 equals/hashCode 逻辑
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值