Lombok 使用教程-@Value | 轻松实现不可变类

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

一、简介

lombok v0.11.4中,@Value被作为实验性功能引入。

lombok v0.11.8以来,@Value不再意味着@With

lombok v0.12.0以来,@Value被提升为lombok主包。

@Value@Data的不可更改变体;默认情况下,所有字段都是privatefinal的,并且不会生成setter。默认情况下,类本身也是final的,因为不可变性不是可以强加给子类的东西。与@Data一样,还生成了有用的toString()equals()hashCode()方法,每个字段都得到一个getter方法,并且还生成了一个覆盖每个参数(除了在字段声明中初始化的final字段)的构造函数。

实际上,@Value是以下内容的缩写:final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter,除了明确包括任何相关方法的实现,只是意味着该部分不会被生成,也不会发出警告。例如,如果你写了你自己的toString,不会发生错误,lombok也不会生成toString。另外,任何显式构造函数,无论参数列表如何,都意味着lombok不会生成一个构造函数。如果你确实想让lombok生成所有参数的构造函数,请在类中添加@AllArgsConstructor。注意,如果@Builder@Value都在一个类上,@Builder想做的包的私有所有参数构造函数会 "胜过"@Value想做的公共构造函数。你可以用@lombok.experimental.Tolerate来标记任何构造函数或方法,以便从lombok中隐藏它们。

我们可以使用字段上的显式访问级别或者使用 @NonFinal 或 @PackagePrivate 注解来覆盖 final-by-default 和 private-by-default 行为。@NonFinal也可以在一个类上使用,以删除final关键字。

可以通过明确使用该注解来覆盖构成@Value的任何 "零件"的任何默认行为。

二、示例比较

1. Lombok 写法

    import lombok.AccessLevel;
    import lombok.experimental.NonFinal;
    import lombok.experimental.Value;
    import lombok.experimental.With;
    import lombok.ToString;
    
    @Value public class ValueExample {
      String name;
      @With(AccessLevel.PACKAGE) @NonFinal int age;
      double score;
      protected String[] tags;
      
      @ToString(includeFieldNames=true)
      @Value(staticConstructor="of")
      public static class Exercise<T> {
        String name;
        T value;
      }
    }

2. Java 标准写法

    import java.util.Arrays;
    
    public final class ValueExample {
      private final String name;
      private int age;
      private final double score;
      protected final String[] tags;
      
      @java.beans.ConstructorProperties({"name", "age", "score", "tags"})
      public ValueExample(String name, int age, double score, String[] tags) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.tags = tags;
      }
      
      public String getName() {
        return this.name;
      }
      
      public int getAge() {
        return this.age;
      }
      
      public double getScore() {
        return this.score;
      }
      
      public String[] getTags() {
        return this.tags;
      }
      
      @java.lang.Override
      public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof ValueExample)) return false;
        final ValueExample other = (ValueExample)o;
        final Object this$name = this.getName();
        final Object other$name = other.getName();
        if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
        if (this.getAge() != other.getAge()) return false;
        if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
        if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
        return true;
      }
      
      @java.lang.Override
      public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final Object $name = this.getName();
        result = result * PRIME + ($name == null ? 43 : $name.hashCode());
        result = result * PRIME + this.getAge();
        final long $score = Double.doubleToLongBits(this.getScore());
        result = result * PRIME + (int)($score >>> 32 ^ $score);
        result = result * PRIME + Arrays.deepHashCode(this.getTags());
        return result;
      }
      
      @java.lang.Override
      public String toString() {
        return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";
      }
      
      ValueExample withAge(int age) {
        return this.age == age ? this : new ValueExample(name, age, score, tags);
      }
      
      public static final class Exercise<T> {
        private final String name;
        private final T value;
        
        private Exercise(String name, T value) {
          this.name = name;
          this.value = value;
        }
        
        public static <T> Exercise<T> of(String name, T value) {
          return new Exercise<T>(name, value);
        }
        
        public String getName() {
          return this.name;
        }
        
        public T getValue() {
          return this.value;
        }
        
        @java.lang.Override
        public boolean equals(Object o) {
          if (o == this) return true;
          if (!(o instanceof ValueExample.Exercise)) return false;
          final Exercise<?> other = (Exercise<?>)o;
          final Object this$name = this.getName();
          final Object other$name = other.getName();
          if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
          final Object this$value = this.getValue();
          final Object other$value = other.getValue();
          if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false;
          return true;
        }
        
        @java.lang.Override
        public int hashCode() {
          final int PRIME = 59;
          int result = 1;
          final Object $name = this.getName();
          result = result * PRIME + ($name == null ? 43 : $name.hashCode());
          final Object $value = this.getValue();
          result = result * PRIME + ($value == null ? 43 : $value.hashCode());
          return result;
        }
        
        @java.lang.Override
        public String toString() {
          return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
        }
      }
    }

三、支持的配置项

lombok.value.flagUsage = [warning | error] (默认: not set)
Lombok@Value的任何用法标记为警告或错误(如果已配置)。

lombok.noArgsConstructor.extraPrivate = [true | false] (默认: false)
如果为truelombok将为任何@Value注释类生成一个私有的无参数构造函数,该构造函数将所有字段设置为默认值(null/0/false)。

四、附属说明

查找有关@Value的“零件”的文档:@ToString@EqualsAndHashCode@AllArgsConstructor@FieldDefaults 和 @Getter

对于具有泛型的类,将静态方法用作构造函数是很有用的,因为通过静态方法推断泛型参数在 java6 中有效并且避免了必须使用菱形运算符。虽然您可以通过应用显式 @AllArgsConstructor(staticConstructor="of") 注释来强制执行此操作,但还有 @Value(staticConstructor="of") 功能,它将使生成的所有参数构造函数私有,并生成公共静态名为 of 的方法是此私有构造函数的包装器。

各种众所周知的关于空性的注解会导致插入空检查并将其复制到相关位置(例如 getter 的方法,以及构造函数和 setter 的参数)。有关更多信息,请参阅 Getter/Setter 文档的附属说明。

@Value 是一个从 v0.11.4 到 v0.11.9 的实验性功能(如@lombok.experimental.Value)。它已被移至核心包中。旧注释仍然存在(并且是别名)。不过,它最终会在未来的版本中被删除。

无法使用@FieldDefaults来“undo”注释类中字段的 private-by-default 和final-by-default方面。在类中的字段上使用@NonFinal@PackagePrivate来重写此行为。

参考文献

【1】@Value | Immutable classes made very easy.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值