当前位置: 首页 > news >正文

Java Lombok @Data 注解用法详解

Lombok 的 @Data 注解是一个极其强大且常用的注解,它旨在极大简化 Java Bean 或值对象(如 POJO)的代码编写。它本质上是多个 Lombok 注解的组合,自动为你生成大量样板代码。

核心功能:

@Data 等价于同时使用了以下注解:

  1. @Getter: 为所有非静态字段生成 public 的 getter 方法。

  2. @Setter: 为所有非 final 且非静态的字段生成 public 的 setter 方法。

  3. @ToString: 生成 toString() 方法,默认包含所有非静态字段。

  4. @EqualsAndHashCode: 生成 equals(Object other) 和 hashCode() 方法,默认使用所有非静态、非瞬态字段(除非用 @EqualsAndHashCode.Exclude 排除)。

  5. @RequiredArgsConstructor: 生成一个包含所有 final 字段以及标记为 @NonNull 且未在声明时初始化的字段的构造函数。

用法:

直接在类声明上方添加 @Data 注解即可。

java

复制

下载

import lombok.Data;@Data
public class User {private final Long id; // 包含在 RequiredArgsConstructor 中private String username;private String email;private int age;private boolean active;// ... 可能还有其他字段
}

Lombok 自动生成的代码等价于:

java

复制

下载

public class User {private final Long id;private String username;private String email;private int age;private boolean active;// @RequiredArgsConstructor 生成的public User(Long id) {this.id = id;}// @Getter 生成的public Long getId() {return this.id;}public String getUsername() {return this.username;}public String getEmail() {return this.email;}public int getAge() {return this.age;}public boolean isActive() { // boolean 类型特殊,getter 通常是 isXxx()return this.active;}// @Setter 生成的 (注意:id 是 final,所以没有 setId)public void setUsername(String username) {this.username = username;}public void setEmail(String email) {this.email = email;}public void setAge(int age) {this.age = age;}public void setActive(boolean active) {this.active = active;}// @EqualsAndHashCode 生成的@Overridepublic boolean equals(Object o) {if (o == this) return true;if (!(o instanceof User)) return false;User other = (User) o;if (!other.canEqual((Object) this)) return false;if (this.getId() == null ? other.getId() != null : !this.getId().equals(other.getId())) return false;if (this.getUsername() == null ? other.getUsername() != null : !this.getUsername().equals(other.getUsername())) return false;if (this.getEmail() == null ? other.getEmail() != null : !this.getEmail().equals(other.getEmail())) return false;if (this.getAge() != other.getAge()) return false;if (this.isActive() != other.isActive()) return false;return true;}@Overridepublic int hashCode() {int PRIME = 59;int result = 1;result = result * PRIME + (this.getId() == null ? 43 : this.getId().hashCode());result = result * PRIME + (this.getUsername() == null ? 43 : this.getUsername().hashCode());result = result * PRIME + (this.getEmail() == null ? 43 : this.getEmail().hashCode());result = result * PRIME + this.getAge();result = result * PRIME + (this.isActive() ? 79 : 97);return result;}// @ToString 生成的@Overridepublic String toString() {return "User(id=" + this.getId() + ", username=" + this.getUsername() + ", email=" + this.getEmail() + ", age=" + this.getAge() + ", active=" + this.isActive() + ")";}
}

关键点解释和注意事项:

  1. 构造函数 (@RequiredArgsConstructor):

    • 只生成包含所有 final 字段和标记为 @NonNull 且未在声明时初始化的字段的构造函数。

    • 如果你需要一个无参构造函数或者包含所有字段的构造函数,需要显式添加 @NoArgsConstructor 或 @AllArgsConstructor

    • 示例: 在上面的 User 类中,只有 id 是 final,所以只生成 User(Long id) 构造函数。如果需要无参构造,要加上 @NoArgsConstructor

  2. Getter/Setter:

    • Getter 对所有字段生成。

    • Setter 只对非 final 且非静态字段生成。

    • 布尔字段 (boolean) 的 getter 默认命名为 isFieldName()

    • 如果需要改变访问级别(如 protected 或包私有)、懒加载 (@Getter(lazy=true)) 或自定义逻辑,应使用单独的 @Getter/@Setter 注解而不是 @Data

  3. toString() (@ToString):

    • 默认包含所有非静态字段。

    • 可以使用 @ToString.Exclude 排除特定字段:@ToString.Exclude private String password;

    • 可以使用 @ToString(onlyExplicitlyIncluded = true) 然后配合 @ToString.Include 来只包含标记的字段。

    • 可以使用 @ToString(callSuper = true) 来包含父类的 toString() 结果(默认是 false)。

  4. equals() 和 hashCode() (@EqualsAndHashCode):

    • 极其重要! 默认使用所有非静态、非瞬态 (transient) 字段来计算。

    • 使用 @EqualsAndHashCode.Exclude 排除特定字段。

    • 使用 @EqualsAndHashCode(onlyExplicitlyIncluded = true) 配合 @EqualsAndHashCode.Include 来只包含标记的字段(推荐做法,避免意外包含不相关字段导致逻辑错误)。

    • 使用 @EqualsAndHashCode(callSuper = true) 在计算时考虑父类的 equals/hashCode(默认是 false)。如果类有继承父类(非 Object),强烈建议仔细考虑是否需要设置 callSuper = true,这通常是需要的,以避免违反等价关系契约。

  5. final 和 @NonNull 字段:

    • final 字段会被包含在 @RequiredArgsConstructor 中,且不会生成 setter。

    • 如果 @NonNull 字段在声明时未初始化,它会被包含在 @RequiredArgsConstructor 中,并且生成的 setter 和构造器会自动添加 null 检查(抛出 NullPointerException)。如果字段在声明时已初始化,则不会被包含在构造器中。

最佳实践和常见场景:

  1. 简单数据传输对象 (DTO) / 值对象 (VO): @Data 是理想选择,能极大简化代码。

  2. JPA/Hibernate 实体 (Entity):

    • 可以使用 @Data

    • 但要非常小心 equals()/hashCode()

      • 避免使用自动生成的代理键 (如 @Id @GeneratedValue) 或者可变字段(如集合关联)来计算 equals/hashCode,尤其是在实体还未持久化(id 为 null)或关联被修改时。推荐使用业务键(如唯一用户名、组合字段)或依赖数据库唯一标识但要确保一致性(有时用 id 但只在持久化后有效)。

      • 通常需要显式配置 @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false) 并用 @EqualsAndHashCode.Include 标记选定的稳定业务键字段。

    • 注意生成的 setter 是 public 的,有时你可能希望控制对某些字段(如关联集合)的修改,这时可能需要使用单独的 @Setter(AccessLevel.PROTECTED) 或避免 setter 而提供业务方法。

    • 小心循环引用在 toString() 中导致 StackOverflowError(尤其在双向关联时),用 @ToString.Exclude 排除关联字段。

  3. 不可变对象: 如果目标是创建不可变对象,将所有字段设为 final,然后使用 @Data (或 @Value)。@Data 会生成包含所有 final 字段的构造器 (@RequiredArgsConstructor),且不会为 final 字段生成 setter。

  4. 需要定制化时: 如果 @Data 的默认行为不完全符合要求(如 toString 格式、equals 逻辑、部分字段不需要 setter/getter、需要其他构造器等),不要犹豫,拆开使用单独的 Lombok 注解(@Getter@Setter@ToString@EqualsAndHashCode@NoArgsConstructor@AllArgsConstructor@RequiredArgsConstructor@Builder 等)@Data 是方便的快捷方式,但不是万能药。

配置依赖 (Maven):

确保在项目的 pom.xml 中添加 Lombok 依赖(作用域为 provided,因为它是编译时注解处理器)和注解处理器路径:

xml

复制

下载

运行

<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version> <!-- 使用最新稳定版本 --><scope>provided</scope></dependency>
</dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version> <!-- 使用兼容版本 --><configuration><source>17</source> <!-- 根据你的JDK版本调整 --><target>17</target><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></path></annotationProcessorPaths></configuration></plugin></plugins>
</build>

IDE 支持:

为了让 IDE(如 IntelliJ IDEA, Eclipse)能识别 Lombok 生成的代码并避免编译错误,必须安装对应的 Lombok 插件。具体安装方法请参考 Lombok 官网或 IDE 的插件市场。

总结:

Lombok 的 @Data 注解通过自动生成 getter、setter、toStringequalshashCode 和特定构造器,显著减少了 Java Bean 中的样板代码,提高了开发效率和代码简洁性。然而,理解其默认行为(特别是关于 equals/hashCode、构造器生成规则和字段排除)以及何时需要定制化(使用单独的 Lombok 注解)至关重要,尤其是在处理 JPA 实体、继承或需要特定行为时。正确使用 @Data 能让你的代码更干净、更易维护。

http://www.xdnf.cn/news/877177.html

相关文章:

  • 量子通信:从科幻走向现实的未来通信技术
  • 四、Sqoop 导入表数据子集
  • 使用C++调用python库
  • 东西方艺术的对话:彰显中国传统艺术之美与价值
  • 主流Agent开发平台学习笔记:扣子罗盘coze loop 功能拆解
  • Vue插件
  • 租物理服务器,如何避开 “高价陷阱”
  • MES管理系统的核心数据采集方式有哪些
  • Linux 环境下 PPP 拨号的嵌入式开发实现
  • CMake在VS中使用远程调试
  • python实现合并多个dot文件
  • linux系统--iptables实战案例
  • 在本地电脑中部署阿里 Qwen3 大模型及连接到 Elasticsearch
  • if(!p)等价于 if(p==0)
  • 【学习笔记】Python金融基础
  • 猎板硬金镀层厚度:新能源汽车高压系统的可靠性基石
  • 压测软件-Jmeter
  • socket是什么
  • SQL进阶之旅 Day 14:数据透视与行列转换技巧
  • 综合案例:斗地主
  • Serverless 在商城活动页面的应用:快速扩缩容与成本控制——基于云函数的秒杀活动场景实践
  • 幂等性:保障系统稳定的关键设计
  • Sentry 的部署方式:自托管与 SaaS 服务
  • arduino D1 UNO R3 使用记录(保姆级教程)
  • CET6 仔细阅读 24年12月第三套-C1 恐惧这一块
  • 电商接口计费标准是什么?
  • FART 精准脱壳:通过配置文件控制脱壳节奏与范围
  • 【算法题】最长回文子串
  • 多线程与fork使用
  • 从繁琐到简易:3 款P图工具解锁图片编辑新体验