Lombok @Value 注解:创建不可变类
一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 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 的 @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
创建不可变对象,能提升数据安全性和一致性。