Lombok @Value 注解:创建不可变类
一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目:《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot 3.x + JDK 21...,点击查看 ; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,点击查看项目介绍 ; 演示链接: http://116.62.199.48:7070/ ; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
截止目前, 星球 内专栏累计输出 110w+ 字,讲解图 4421+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 4000+ 小伙伴加入学习 ,欢迎点击围观
Lombok 的 @Value 注解用于简化不可变对象的创建。不可变对象(Immutable Object)在创建后,其内部状态无法改变,具备线程安全的特性,适合并发环境中共享数据的场景。@Value 注解相当于 @Getter、@AllArgsConstructor、@ToString、@EqualsAndHashCode 和 final 组合,因此非常适合用来定义数据传输对象(DTO)或作为业务逻辑中不可变的核心数据结构。
基本用法
在类上添加 @Value 注解后,Lombok 会自动将所有字段设为 final 并生成只读的 getter,禁止字段的修改方法。@Value 类似于 @Data,但适用于不可变对象。
示例
import lombok.Value;
@Value
public class User {
String name;
int age;
}
上述代码自动生成以下内容:
final修饰符:所有字段都自动变为final,只能在构造时赋值。getter方法:为每个字段生成public的getter方法。toString()方法:生成包含所有字段的toString()方法。equals()和hashCode()方法:基于字段生成对象的equals()和hashCode()方法。- 全参构造方法:生成一个包含所有字段的构造方法,便于直接赋值。
创建 User 对象时可以指定字段的初始值:
User user = new User("Alice", 25);
System.out.println(user.getName()); // 输出: Alice
System.out.println(user.getAge()); // 输出: 25
此 User 类生成的对象将是不可变的,因为它的所有字段都为 final,没有 setter 方法。
@Value 注解的默认特性
- 不可变性:所有字段自动设为
final,对象创建后其状态不可更改。 - 私有构造方法:除非显式定义,
@Value会默认生成一个私有的无参构造器。一般情况下不会用到,因为@Value的对象要求全部字段初始化。 - 序列化支持:
@Value类默认实现Serializable接口,非常适合在分布式环境中传输数据。
@Value 与 @Data 的区别
@Value 和 @Data 都能生成 getter、toString()、equals() 和 hashCode() 方法,但 @Value 注解的类具有不可变性,不会生成 setter 方法。@Value 适合不希望被修改的数据对象,而 @Data 更适合那些需要修改的普通 Java Bean。
@Value 与手动创建不可变对象的对比
在没有 Lombok 的情况下,手动创建不可变对象需要将字段设为 final,创建全参构造方法,并编写 getter、toString()、equals() 和 hashCode() 方法。相比之下,@Value 注解大大减少了代码量。
手动实现不可变类示例
public final class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public boolean equals(Object o) {
// 实现 equals 逻辑
}
@Override
public int hashCode() {
// 实现 hashCode 逻辑
}
@Override
public String toString() {
return "User(name=" + name + ", age=" + age + ")";
}
}
使用 @Value 可以简化以上所有操作。
@Value 与可变集合的组合
虽然 @Value 保证了对象的不可变性,但如果字段是集合类型(如 List、Map 等),则无法保证集合内容的不可变性。为实现完全不可变性,可以使用 Collections.unmodifiableList() 等方法将集合转换为不可变的视图。
示例
import lombok.Value;
import java.util.List;
import java.util.Collections;
@Value
public class User {
String name;
List<String> hobbies;
public User(String name, List<String> hobbies) {
this.name = name;
this.hobbies = Collections.unmodifiableList(hobbies);
}
}
这段代码确保了 hobbies 字段的内容在对象创建后也不可修改。
小结
Lombok 的 @Value 注解是创建不可变对象的快捷方式,具备以下优点:
- 自动将字段设为
final,生成只读的getter,确保对象不可变。 - 生成
toString()、equals()和hashCode()方法,使对象支持打印和比较。 - 提供全参构造方法,便于快速创建对象。
- 简化了不可变对象的实现,适合数据传输对象(DTO)和并发环境中共享的数据结构。
在多线程和分布式环境中,通过 @Value 创建不可变对象,能提升数据安全性和一致性。