Lombok @Data 注解:快速生成类常用方法
一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
截止目前, 星球 内专栏累计输出 66w+ 字,讲解图 2896+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2300+ 小伙伴加入学习 ,欢迎点击围观
一 、什么是 Lombok @Data 注解?
在 Lombok 中,
@Data
是一个集合注解,它整合了多个 Lombok 注解,用于快速生成实体类对象所需的常用方法。
一个 @Data
注解相当于同时使用了如下注解 :
-
@Getter
和@Setter
:为每个字段生成getter
和setter
方法; -
@ToString
:生成toString()
方法,打印对象的所有字段; -
@EqualsAndHashCode
:生成equals()
和hashCode()
方法,基于字段值实现对象比较; -
@RequiredArgsConstructor
:生成包含final
和@NonNull
字段的构造方法;
二、对比编译后的源码
先来看看下面这两段 Lombok 注解使用示例:
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
public class User1 {
private Long id;
private String username;
// 更多字段省略 ...
}
@Data
public class User2 {
private Long id;
private String username;
// 更多字段省略 ...
}
编译代码,看看 Lombok 为这两个实体类生成的代码:
User1.java :
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.quanxiaoha.coursefrontend.model;
public class User1 {
private Long id;
private String username;
public Long getId() {
return this.id;
}
public String getUsername() {
return this.username;
}
public void setId(final Long id) {
this.id = id;
}
public void setUsername(final String username) {
this.username = username;
}
public User1() {
}
public String toString() {
return "User1(id=" + this.getId() + ", username=" + this.getUsername() + ")";
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User1)) {
return false;
} else {
User1 other = (User1)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id != null) {
return false;
}
} else if (!this$id.equals(other$id)) {
return false;
}
Object this$username = this.getUsername();
Object other$username = other.getUsername();
if (this$username == null) {
if (other$username != null) {
return false;
}
} else if (!this$username.equals(other$username)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof User1;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $username = this.getUsername();
result = result * 59 + ($username == null ? 43 : $username.hashCode());
return result;
}
}
User2.java :
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.quanxiaoha.coursefrontend.model;
public class User2 {
private Long id;
private String username;
public User2() {
}
public Long getId() {
return this.id;
}
public String getUsername() {
return this.username;
}
public void setId(final Long id) {
this.id = id;
}
public void setUsername(final String username) {
this.username = username;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User2)) {
return false;
} else {
User2 other = (User2)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id != null) {
return false;
}
} else if (!this$id.equals(other$id)) {
return false;
}
Object this$username = this.getUsername();
Object other$username = other.getUsername();
if (this$username == null) {
if (other$username != null) {
return false;
}
} else if (!this$username.equals(other$username)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof User2;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $username = this.getUsername();
result = result * 59 + ($username == null ? 43 : $username.hashCode());
return result;
}
public String toString() {
return "User2(id=" + this.getId() + ", username=" + this.getUsername() + ")";
}
}
通过对比,会发现两个类生成的代码一致,包含:
- 生成了所有字段的
get/set
方法; - 实体类的无参构造器;
toString()
方法;hashCode()
方法;equals()
方法;
三、Lombok @Data 注解是何时工作的?
Lombok @Data
注解会在代码的编译阶段,为你静默生成相关样板代码。
四、staticConstructor 参数
先看一段示例代码:
@Data(staticConstructor = "create")
public class User2 {
private Long id;
private String username;
// 更多字段省略 ...
}
如果你为 @Data
注解指定了 staticConstructor
参数,再次编译代码,看看实际生成的代码:
由图可知,@Data(staticConstructor = "create")
生成了一个名为 create()
静态实体类生成方法,同时私有化了无参构造器。
五、Lombok @Data 排除指定字段
@Data
注解生成的模板方法中,默认会带上所有字段,如果针对某个字段不想生成 get/set
方法,或者是 toString()
、equals()
、hashCode()
方法排除某个字段的判断,示例代码如下:
@Data
public class User3 {
// 不生成此字段的 set 方法
@Setter(value = AccessLevel.NONE)
private Long id;
// 不生成此字段的 get 方法
@Getter(value = AccessLevel.NONE)
private String username;
// toString() 方法中不打印此字段
@ToString.Exclude
private String email;
// 1. equals() 和 hashCode() 方法中排除此字段的判断
// 2. toString() 方法中不打印此字段
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Integer sex;
}
六、关于 Lombok 参数构造器
如果仅添加 @Data 注解,默认只会生成一个无参的构造器;当同时添加 @Data
和 @Builder
注解时,仅会生成一个全参构造器。小哈在日常项目中,通常会在实体类上额外添加 @AllArgsConstructor
、@NoArgsConstructor
注解, 示例代码如下:
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User4 {
private Long id;
private String username;
// 更多字段省略 ...
}
这样,该实体类就基本拥有了常用的一些模板方法,包括 builder
构造器模式、无参构造器、全参构造器等。
七、结语
本小节中,我们学习了 Lombok 的 @Data 注解,以及通过简单的代码示例,知道了如何在项目中使用它。总之,Lombok 是一个被广泛应用于生产环境的成熟工具,它可以帮助开发者生成实体类通用的一些样板代码,从而帮助我们节省大量的开发时间,还没有使用它的小伙伴们,可以赶快安排上了。