Lombok @Value 注解:创建不可变类

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

截止目前, 星球 内专栏累计输出 72w+ 字,讲解图 3103+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2400+ 小伙伴加入学习 ,欢迎点击围观

Lombok 的 @Value 注解用于简化不可变对象的创建。不可变对象(Immutable Object)在创建后,其内部状态无法改变,具备线程安全的特性,适合并发环境中共享数据的场景。@Value 注解相当于 @Getter@AllArgsConstructor@ToString@EqualsAndHashCodefinal 组合,因此非常适合用来定义数据传输对象(DTO)或作为业务逻辑中不可变的核心数据结构。

基本用法

在类上添加 @Value 注解后,Lombok 会自动将所有字段设为 final 并生成只读的 getter,禁止字段的修改方法。@Value 类似于 @Data,但适用于不可变对象。

示例

import lombok.Value;

@Value
public class User {
    String name;
    int age;
}

上述代码自动生成以下内容:

  • final 修饰符:所有字段都自动变为 final,只能在构造时赋值。
  • getter 方法:为每个字段生成 publicgetter 方法。
  • 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 注解的默认特性

  1. 不可变性:所有字段自动设为 final,对象创建后其状态不可更改。
  2. 私有构造方法:除非显式定义,@Value 会默认生成一个私有的无参构造器。一般情况下不会用到,因为 @Value 的对象要求全部字段初始化。
  3. 序列化支持@Value 类默认实现 Serializable 接口,非常适合在分布式环境中传输数据。

@Value@Data 的区别

@Value@Data 都能生成 gettertoString()equals()hashCode() 方法,但 @Value 注解的类具有不可变性,不会生成 setter 方法。@Value 适合不希望被修改的数据对象,而 @Data 更适合那些需要修改的普通 Java Bean。

@Value 与手动创建不可变对象的对比

在没有 Lombok 的情况下,手动创建不可变对象需要将字段设为 final,创建全参构造方法,并编写 gettertoString()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 保证了对象的不可变性,但如果字段是集合类型(如 ListMap 等),则无法保证集合内容的不可变性。为实现完全不可变性,可以使用 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 创建不可变对象,能提升数据安全性和一致性。