Java神奇工具——Lombok[最全]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/IPOmonkey/article/details/83512308

最近刚接触,结果官网访问速度很慢,网上博客又没有介绍全,打算自己做个详细的,以防后面复习使用。

目录

 

Lombok

如何用Lombok——两种方法

有哪些注解可以使用呢[1.16.18版本一共18个注解,有一个注解不推荐使用]

@AllArgsConstructor / @NoArgsConstructor / @RequiredArgsConstructor

@Builder

@ Builder.Default

@Singular

@Cleanup

@Data

@Delegate

@EqualsAndHashCode

@Generated

@Getter / @Setter

@NonNull

@SneakyThrows

@Synchronized

@ToString

@log

val

@Value


Lombok

这个是Java一个神奇工具,使用注解,减少Java的冗余代码。最低支持Jdk1.6【我用的是Jdk1.8】

官网:https://www.projectlombok.org

github源码地址:https://github.com/rzwitserloot/lombok【又是个胖胖的大佬写的】

官网上对此也有介绍:Lombok项目是一个Java库, 它可以自动插入你的编辑器并构建工具,为你的Java程序添加兴趣。永远不需要再写getter方法或者equals方法了。更早地去接触Java地未来,就像接触val一样。

显而易见,这个工具就是让我们在建立实体类的时候,变得简单,轻松。

如何用Lombok——两种方法

1.如果你是IDEA,可以直接安装插件

ideaå®è£Lombok

2.如果你是Maven项目,可以添加到pom.xml文件中

中央仓库选择版本:https://mvnrepository.com/artifact/org.projectlombok/lombok

这边使用人数最多的1.16.18版本

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
</dependency>

有哪些注解可以使用呢[1.16.18版本一共18个注解,有一个注解不推荐使用]

 @AllArgsConstructor会生成全参构造器。

@NoArgsConstructor会生成无参构造器。但是对于具有约束的字段(如@NonNull字段),不会生成任何检查,因此请注意,在稍后正确初始化这些字段之前,通常不会满足这些约束。某些java构造(例如hibernate和Service Provider Interface)需要no-args构造函数。此批注主要与@Data生成注释的其他构造函数之一或其中一个配合使用。

@RequiredArgsConstructor会将未初始化的final变量和带@NonNull的变量作为构造器参数。

  • @AllArgsConstructor / @NoArgsConstructor / @RequiredArgsConstructor

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;

@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
  private int x, y;
  @NonNull private T description;
  
  @NoArgsConstructor
  public static class NoArgsExample {
    @NonNull private String field;
  }
}

相当于:

public class ConstructorExample<T> {
  private int x, y;
  @NonNull private T description;
  
  private ConstructorExample(T description) {
    if (description == nullthrow new NullPointerException("description");
    this.description = description;
  }
  
  public static <T> ConstructorExample<T> of(T description) {
    return new ConstructorExample<T>(description);
  }
  
  @java.beans.ConstructorProperties({"x""y""description"})
  protected ConstructorExample(int x, int y, T description) {
    if (description == nullthrow new NullPointerException("description");
    this.x = x;
    this.y = y;
    this.description = description;
  }
  
  public static class NoArgsExample {
    @NonNull private String field;
    
    public NoArgsExample() {
    }
  }
}
  • @Builder

@Builder 允许您使用以下代码自动生成使您的类可实例化所需的代码:
Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();

@Builder可以放在类,构造函数或方法上。虽然“在类上”和“在构造函数上”模式是最常见的用例,但@Builder最容易用“方法”用例来解释。

@Builder(从现在开始调用目标)注释的方法会导致生成以下7件事:

深入了解网址:https://projectlombok.org/features/Builder

  • 一个名为的内部静态类FooBuilder,具有与静态方法相同的类型参数(称为构建器)。
  • 构建器中目标的每个参数的一个私有非静态非最终字段。
  • 构建器中:一个包私有no-args空构造函数。
  • 构建器中:对于目标的每个参数,类似于“setter”的方法:它具有与该参数相同的类型和相同的名称。它返回构建器本身,以便可以链接setter调用,如上例所示。
  • 构建器中build()调用方法的方法,传入每个字段。它返回与目标返回的相同类型。
  • 构建器中:一个明智的toString()实现。
  • 在包含目标的类中:一种builder()方法,它创建构建器的新实例。

@ Builder.Default

如果在构建会话期间从未设置某个字段/参数,则它始终为0 / null/ false。如果您已经放置@Builder了一个类(而不是方法或构造函数),则可以直接在该字段上指定默认值,并使用以下内容对该字段进行注释@Builder.Default
@Builder.Default private final long created = System.currentTimeMillis();

@Singular

通过使用注释注释其中一个参数(如果使用方法或构造函数进行注释@Builder)或字段(如果使用注释类@Builder@Singular,lombok将该构建器节点视为集合,并生成2个“加法器”方法而不是“ setter'方法。一个向集合添加单个元素,另一个将另一个集合的所有元素添加到集合中。将不生成仅设置集合(替换已添加的任何内容)的setter。还生成了“清晰”方法。这些“单一”构建器非常复杂,以保证以下属性:

  • 调用时build(),生成的集合将是不可变的。
  • 在调用之后调用“adder”方法之一或“clear”方法build()不会修改任何已生成的对象,并且如果build()稍后再次调用,则会生成自生成构建器以来添加了所有元素的另一个集合。
  • 生成的集合将被压缩到最小的可行格式,同时保持高效。

@Singular只能应用于lombok已知的集合类型。目前,支持的类型是:

  • java.util
    • IterableCollectionListArrayList在一般情况下由压缩的不可修改的支持)。
    • SetSortedSetNavigableSet(由一个适当的大小不可修改HashSetTreeSet在一般情况下支持)。
    • MapSortedMapNavigableMap(由一个适当的大小不可修改HashMapTreeMap在一般情况下支持)。
import lombok.Builder;
import lombok.Singular;
import java.util.Set;

@Builder
public class BuilderExample {
  @Builder.Default private long created = System.currentTimeMillis();
  private String name;
  private int age;
  @Singular private Set<String> occupations;
}

相当于:

import java.util.Set;

public class BuilderExample {
  private long created;
  private String name;
  private int age;
  private Set<String> occupations;
  
  BuilderExample(String name, int age, Set<String> occupations) {
    this.name = name;
    this.age = age;
    this.occupations = occupations;
  }
  
  private static long $default$created() {
    return System.currentTimeMillis();
  }
  
  public static BuilderExampleBuilder builder() {
    return new BuilderExampleBuilder();
  }
  
  public static class BuilderExampleBuilder {
    private long created;
    private boolean created$set;
    private String name;
    private int age;
    private java.util.ArrayList<String> occupations;
    
    BuilderExampleBuilder() {
    }
    
    public BuilderExampleBuilder created(long created) {
      this.created = created;
      this.created$set = true;
      return this;
    }
    
    public BuilderExampleBuilder name(String name) {
      this.name = name;
      return this;
    }
    
    public BuilderExampleBuilder age(int age) {
      this.age = age;
      return this;
    }
    
    public BuilderExampleBuilder occupation(String occupation) {
      if (this.occupations == null) {
        this.occupations = new java.util.ArrayList<String>();
      }
      
      this.occupations.add(occupation);
      return this;
    }
    
    public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
      if (this.occupations == null) {
        this.occupations = new java.util.ArrayList<String>();
      }

      this.occupations.addAll(occupations);
      return this;
    }
    
    public BuilderExampleBuilder clearOccupations() {
      if (this.occupations != null) {
        this.occupations.clear();
      }
      
      return this;
    }

    public BuilderExample build() {
      // complicated switch statement to produce a compact properly sized immutable set omitted.
      Set<String> occupations = ...;
      return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations);
    }
    
    @java.lang.Override
    public String toString() {
      return "BuilderExample.BuilderExampleBuilder(created = " this.created + ", name = " this.name + ", age = " this.age + ", occupations = " this.occupations + ")";
    }
  }
}

您可以使用@Cleanup以确保在代码执行路径退出当前作用域之前自动清除给定资源。您可以通过使用注释注释任何局部变量声明来执行此操作@Cleanup@Cleanup InputStream in = new FileInputStream("some/file");  

  • @Cleanup

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] argsthrows IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1break;
      out.write(b, 0, r);
    }
  }
}

相当于

import java.io.*;

public class CleanupExample {
  public static void main(String[] argsthrows IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1break;
          out.write(b, 0, r);
        }
      finally {
        if (out != null) {
          out.close();
        }
      }
    finally {
      if (in != null) {
        in.close();
      }
    }
  }
}

@Data是一个方便的快捷方式注释,它捆绑了@ToString@EqualsAndHashCode@Getter/@Setter@RequiredArgsConstructor它们的特征:换句话说,@Data生成通常与简单POJO(普通旧Java对象)和bean相关联的所有样板:所有字段的getter,所有非的setter最终场,和适当的toStringequalshashCode实现涉及类的字段和初始化所有final字段,以及不具有初始已打上所有非最终场构造@NonNull,以保证该领域从来都不是空值。

  • @Data

import lombok.AccessLevel;
import lombok.Setter;
import lombok.Data;
import lombok.ToString;

@Data public class DataExample {
  private final String name;
  @Setter(AccessLevel.PACKAGEprivate int age;
  private double score;
  private String[] tags;
  
  @ToString(includeFieldNames=true)
  @Data(staticConstructor="of")
  public static class Exercise<T> {
    private final String name;
    private final T value;
  }
}

 相当于:

import java.util.Arrays;

public class DataExample {
  private final String name;
  private int age;
  private double score;
  private String[] tags;
  
  public DataExample(String name) {
    this.name = name;
  }
  
  public String getName() {
    return this.name;
  }
  
  void setAge(int age) {
    this.age = age;
  }
  
  public int getAge() {
    return this.age;
  }
  
  public void setScore(double score) {
    this.score = score;
  }
  
  public double getScore() {
    return this.score;
  }
  
  public String[] getTags() {
    return this.tags;
  }
  
  public void setTags(String[] tags) {
    this.tags = tags;
  }
  
  @Override public String toString() {
    return "DataExample(" this.getName() ", " this.getAge() ", " this.getScore() ", " + Arrays.deepToString(this.getTags()) ")";
  }
  
  protected boolean canEqual(Object other) {
    return other instanceof DataExample;
  }
  
  @Override public boolean equals(Object o) {
    if (o == thisreturn true;
    if (!(instanceof DataExample)) return false;
    DataExample other = (DataExampleo;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (this.getAge() != other.getAge()) return false;
    if (Double.compare(this.getScore(), other.getScore()) != 0return false;
    if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
    return true;
  }
  
  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.getScore());
    result = (result*PRIME(this.getName() == null 43 this.getName().hashCode());
    result = (result*PRIMEthis.getAge();
    result = (result*PRIME(int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME+ Arrays.deepHashCode(this.getTags());
    return result;
  }
  
  public static 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;
    }
    
    @Override public String toString() {
      return "Exercise(name=" this.getName() ", value=" this.getValue() ")";
    }
    
    protected boolean canEqual(Object other) {
      return other instanceof Exercise;
    }
    
    @Override public boolean equals(Object o) {
      if (o == thisreturn true;
      if (!(instanceof Exercise)) return false;
      Exercise<?> other = (Exercise<?>o;
      if (!other.canEqual((Object)this)) return false;
      if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
      if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
      return true;
    }
    
    @Override public int hashCode() {
      final int PRIME = 59;
      int result = 1;
      result = (result*PRIME(this.getName() == null 43 this.getName().hashCode());
      result = (result*PRIME(this.getValue() == null 43 this.getValue().hashCode());
      return result;
    }
  }
}
  • @Delegate

NEW IN Lombok 0.10: Any field or no-argument method can be annotated with @Delegate to let lombok generate delegate methods that forward the call to this field (or the result of invoking this method).

Lombok delegates all public methods of the field's type (or method's return type), as well as those of its supertype except for all methods declared in java.lang.Object.

You can pass any number of classes into the @Delegate annotation's types parameter. If you do that, then lombok will delegate all public methods in those types (and their supertypes, except java.lang.Object) instead of looking at the field/method's type.

All public non-Object methods that are part of the calculated type(s) are copied, whether or not you also wrote implementations for those methods. That would thus result in duplicate method errors. You can avoid these by using the @Delegate(excludes=SomeType.class) parameter to exclude all public methods in the excluded type(s), and their supertypes.

To have very precise control over what is delegated and what isn't, write private inner interfaces with method signatures, then specify these private inner interfaces as types in @Delegate(types=PrivateInnerInterfaceWithIncludesList.class, excludes=SameForExcludes.class).

  • @EqualsAndHashCode

  • @Generated

  • @Getter / @Setter

  • @NonNull

您可以在方法或构造函数的参数上使用@NonNull让Lombok自动进行非空检测。 

import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;
  
  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

相当于: 

import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;
  
  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person is marked @NonNull but is null");
    }
    this.name = person.getName();
  }
}
  • @SneakyThrows

@SneakyThrows可以用来偷偷抛出已检查的异常而不在方法的throws子句中实际声明这一点。当然,应该谨慎使用这种有争议的能力。由lombok生成的代码不会忽略,包装,替换或以其他方式修改抛出的已检查异常; 它只是伪造了编译器。在JVM(类文件)级别上,无论方法的throws子句如何,都可以抛出所有异常(无论是否已检查),这就是为什么这样做的原因。

当您想要选择退出已检查的异常机制时,常见的用例围绕两种情况:

  • 一个不必要的严格的接口,例如Runnable- 无论是否传播出你的run()方法,检查与否,它都将被传递给Thread未处理的异常处理程序。捕获已检查的异常并将其包装在某种情况RuntimeException下只会模糊问题的真正原因。
  • 一个'不可能'的例外。例如,new String(someByteArray, "UTF-8");声明它可以抛出UnsupportedEncodingException但是根据JVM规范,UTF-8 必须始终可用。一个UnsupportedEncodingException在这里大约是有可能的ClassNotFoundError,当你使用一个String对象,而你没有捕获这些异常。
import lombok.SneakyThrows;

public class SneakyThrowsExample implements Runnable {
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) {
    return new String(bytes, "UTF-8");
  }
  
  @SneakyThrows
  public void run() {
    throw new Throwable();
  }
}

 相当于:

import lombok.Lombok;

public class SneakyThrowsExample implements Runnable {
  public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
  }
  
  public void run() {
    try {
      throw new Throwable();
    catch (Throwable t) {
      throw Lombok.sneakyThrow(t);
    }
  }
}

 synchronized done right: Don't expose your locks.

  • @Synchronized

@Synchronizedsynchronized方法修饰符的更安全的变体。同样synchronized,注释只能用于静态和实例方法。它的操作类似于synchronized关键字,但它锁定在不同的对象上。关键字锁定this,但注释锁定在名为的字段上$lock,该字段是私有的。
如果该字段不存在,则会为您创建该字段。如果您注释static方法,则注释将锁定在名为的静态字段上$LOCK

如果需要,您可以自己创建这些锁。在$lock$LOCK领域会当然不会,如果你已经自己原创生成的。您还可以选择锁定另一个字段,方法是将其指定为@Synchronized注释的参数。在此用法变体中,不会自动创建字段,您必须自己显式创建它们,否则将发出错误。

import lombok.Synchronized;

public class SynchronizedExample {
  private final Object readLock = new Object();
  
  @Synchronized
  public static void hello() {
    System.out.println("world");
  }
  
  @Synchronized
  public int answerToLife() {
    return 42;
  }
  
  @Synchronized("readLock")
  public void foo() {
    System.out.println("bar");
  }
}

相当于:

public class SynchronizedExample {
  private static final Object $LOCK = new Object[0];
  private final Object $lock = new Object[0];
  private final Object readLock = new Object();
  
  public static void hello() {
    synchronized($LOCK) {
      System.out.println("world");
    }
  }
  
  public int answerToLife() {
    synchronized($lock) {
      return 42;
    }
  }
  
  public void foo() {
    synchronized(readLock) {
      System.out.println("bar");
    }
  }
}

No need to start a debugger to see your fields: Just let lombok generate a toString for you!

  • @ToString

可以使用@ToStringlombok生成toString()方法的实现来注释任何类定义。默认情况下,它会按顺序打印您的类名以及每个字段,并以逗号分隔。

通过将includeFieldNames参数设置为true,您可以为toString()方法的输出添加一些清晰度(但也有一些长度)。

默认情况下,将打印所有非静态字段。如果要跳过某些字段,可以使用标注这些字段@ToString.Exclude。或者,您可以使用标准确定要使用的@ToString(onlyExplicitlyIncluded = true)字段,然后标记要包含的每个字段@ToString.Include

import lombok.ToString;

@ToString
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(510);
  private String[] tags;
  @ToString.Exclude private int id;
  
  public String getName() {
    return this.name;
  }
  
  @ToString(callSuper=true, includeFieldNames=true)
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

 相当于:

import java.util.Arrays;

public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(510);
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.getName();
  }
  
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
    
    @Override public String toString() {
      return "Square(super=" super.toString() ", width=" this.width + ", height=" this.height + ")";
    }
  }
  
  @Override public String toString() {
    return "ToStringExample(" this.getName() ", " this.shape + ", " + Arrays.deepToString(this.tags")";
  }
}
  • @log

你把@Log你的类的变体(适用于你使用的日志系统); 然后,您有一个静态的final log字段,初始化为您的类的名称,然后您可以使用它来编写日志语句。

有几种选择:

@CommonsLog

private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Flogger

 private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();

@JBossLog

 private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);

@Log

private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j

private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2

private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

@XSlf4j

private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

默认情况下,记录器的主题(或名称)将是使用@Log注释注释的类的类名。可以通过指定topic参数来自定义。例如:@XSlf4j(topic="reporting")

import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;

@Log
public class LogExample {
  
  public static void main(String... args) {
    log.severe("Something's wrong here");
  }
}

@Slf4j
public class LogExampleOther {
  
  public static void main(String... args) {
    log.error("Something else is wrong here");
  }
}

@CommonsLog(topic="CounterLog")
public class LogExampleCategory {

  public static void main(String... args) {
    log.error("Calling the 'CounterLog' with a message");
  }
}

 相当于:

public class LogExample {
  private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
  
  public static void main(String... args) {
    log.severe("Something's wrong here");
  }
}

public class LogExampleOther {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
  
  public static void main(String... args) {
    log.error("Something else is wrong here");
  }
}

public class LogExampleCategory {
  private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");

  public static void main(String... args) {
    log.error("Calling the 'CounterLog' with a message");
  }
}

Finally! Hassle-free final local variables.

  • val

您可以使用val本地变量声明的类型,而不是实际写入类型。执行此操作时,将从初始化表达式推断出类型。本地变量也将成为最终变量。此功能仅适用于局部变量和foreach循环,而不适用于字段。初始化表达式是必需的。

val实际上是一种“类型”,并且作为lombok包中的真实类存在。您必须导入它才能使val工作(或lombok.val用作类型)。在本地变量声明中存在此类型会触发添加final关键字以及复制覆盖“伪” val类型的初始化表达式的类型。

警告:此功能目前在NetBeans中不起作用。

import java.util.ArrayList;
import java.util.HashMap;
import lombok.val;

public class ValExample {
  public String example() {
    val example = new ArrayList<String>();
    example.add("Hello, World!");
    val foo = example.get(0);
    return foo.toLowerCase();
  }
  
  public void example2() {
    val map = new HashMap<Integer, String>();
    map.put(0"zero");
    map.put(5"five");
    for (val entry : map.entrySet()) {
      System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
    }
  }
}

 相当于:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class ValExample {
  public String example() {
    final ArrayList<String> example = new ArrayList<String>();
    example.add("Hello, World!");
    final String foo = example.get(0);
    return foo.toLowerCase();
  }
  
  public void example2() {
    final HashMap<Integer, String> map = new HashMap<Integer, String>();
    map.put(0"zero");
    map.put(5"five");
    for (final Map.Entry<Integer, String> entry : map.entrySet()) {
      System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
    }
  }
}
  • @Value

Immutable classes made very easy.

@Value是不可变的变体@Data; 所有字段由privatefinal默认情况下,也不会产生setter方法。类本身也是final默认生成的,因为不可变性不是可以强制进入子类的东西。像@Data,有用的toString()equals()并且hashCode()也被生成的方法,每个字段得到,其覆盖每个参数(除了吸气剂的方法,和一个构造final了在字段声明初始化字段)也被产生。

在实践中,@Value是:的简写final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter,除了明确包括任何相关方法的实现只是意味着不会生成部分并且不会发出警告。例如,如果您自己编写toString,则不会发生错误,并且lombok不会生成错误toString。此外,任何显式构造函数,无论参数列表,都意味着lombok不会生成构造函数。如果你确实希望lombok生成all-args构造函数,请添加@AllArgsConstructor到类中。您可以使用任何构造函数或方法标记@lombok.experimental.Tolerate它们以隐藏它们。

import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Value;
import lombok.experimental.Wither;
import lombok.ToString;

@Value public class ValueExample {
  String name;
  @Wither(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;
  }
}

相当于:

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 == thisreturn true;
    if (!(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()) != 0return 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 == thisreturn true;
      if (!(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() ")";
    }
  }
}

猜你喜欢

转载自blog.csdn.net/IPOmonkey/article/details/83512308