Contents

Immutables简介

1. 简介

在本文中,我们将展示如何使用Immutables 库。

该库由注解和注解处理器组成,用于生成和使用可序列化和可定制的不可变对象。

2.Maven依赖

为了在项目中使用 Immutables,您需要将以下依赖项添加到pom.xml文件的依赖项部分:

<dependency>
    <groupId>org.immutables</groupId>
    <artifactId>value</artifactId>
    <version>2.2.10</version>
    <scope>provided</scope>
</dependency>

由于在运行时不需要此工件,因此建议指定提供的范围。

可以在此处 找到该库的最新版本。

3. 不可变

该库从抽象类型生成不可变对象:InterfaceClassAnnotation

实现这一点的关键是正确使用*@Value.Immutable注解。**它生成带注解类型的不可变版本,并在其名称前加上Immutable*关键字**。

如果我们尝试生成一个名为“ X ”的类的不可变版本,它将生成一个名为*“ImmutableX”*的类。生成的类不是递归不可变的,因此最好记住这一点。

还有一个简短的说明——因为 Immutables 使用注解处理,所以您需要记住在 IDE 中启用注解处理。

3.1. 将*@Value.ImmutableAbstract Classes Interfaces*一起使用

让我们创建一个简单的抽象类Person,它包含两个表示要生成的字段的abstract访问器方法,然后使用*@Value.Immutable*注解对该类进行注解:

@Value.Immutable
public abstract class Person {
    abstract String getName();
    abstract Integer getAge();
}

注解处理完成后,我们可以在target/generated-sources目录中找到一个可以使用的、新生成的ImmutablePerson类**:

@Generated({"Immutables.generator", "Person"})
public final class ImmutablePerson extends Person {
    private final String name;
    private final Integer age;
    private ImmutablePerson(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    @Override
    String getName() {
        return name;
    }
    @Override
    Integer getAge() {
        return age;
    }
    // toString, hashcode, equals, copyOf and Builder omitted
}

生成的类带有实现的toStringhashcodeequals方法和一个 stepbuilder ImmutablePerson.Builder。请注意,生成的构造函数具有private访问权限。

为了构造ImmutablePerson类的实例,我们需要使用构建器或静态方法ImmutablePerson.copyOf,它可以从Person对象创建ImmutablePerson副本。

如果我们想使用构建器构造一个实例,我们可以简单地编写代码:

ImmutablePerson john = ImmutablePerson.builder()
  .age(42)
  .name("John")
  .build();

生成的类是不可变的,这意味着它们不能被修改。如果要修改已经存在的对象,可以使用“ withX ”方法之一,它不会修改原始对象,而是使用修改后的字段创建新实例。

让我们更新john 的年龄并创建一个新的john43对象:

ImmutablePerson john43 = john.withAge(43);

在这种情况下,以下断言将是正确的:

assertThat(john).isNotSameAs(john43);
assertThat(john.getAge()).isEqualTo(42);

4. 其他实用程序

如果不能自定义,这样的类生成不会很有用。Immutables 库附带一组附加注解,可用于自定义*@Value.Immutable*的输出。要查看所有这些,请参阅 Immutables 的文档

4.1. @Value.Parameter注解

@Value.Parameter注解可用于指定应为其生成构造方法的字段。

如果你像这样注解你的类:

@Value.Immutable
public abstract class Person {
    @Value.Parameter
    abstract String getName();
    @Value.Parameter
    abstract Integer getAge();
}

可以通过以下方式实例化它:

ImmutablePerson.of("John", 42);

4.2. @Value.Default注解

@Value.Default注解允许您指定在未提供初始值时应使用的默认值。为此,您需要创建一个返回固定值的非抽象访问器方法并使用*@Value.Default*对其进行注解:

@Value.Immutable
public abstract class Person {
    abstract String getName();
    @Value.Default
    Integer getAge() {
        return 42;
    }
}

以下断言将是正确的:

ImmutablePerson john = ImmutablePerson.builder()
  .name("John")
  .build();
assertThat(john.getAge()).isEqualTo(42);

4.3. @Value.Auxiliary注解

@Value.Auxiliary注解可用于注解将存储在对象实例中的属性,但会被equalshashCodetoString实现忽略。

如果你像这样注解你的类:

@Value.Immutable
public abstract class Person {
    abstract String getName();
    abstract Integer getAge();
    @Value.Auxiliary
    abstract String getAuxiliaryField();
}

使用辅助字段时,以下断言将成立:

ImmutablePerson john1 = ImmutablePerson.builder()
  .name("John")
  .age(42)
  .auxiliaryField("Value1")
  .build();
ImmutablePerson john2 = ImmutablePerson.builder()
  .name("John")
  .age(42)
  .auxiliaryField("Value2")
  .build();
assertThat(john1.equals(john2)).isTrue();
assertThat(john1.toString()).isEqualTo(john2.toString());
assertThat(john1.hashCode()).isEqualTo(john2.hashCode());

4.4. *@Value.Immutable(Prehash = True)*注解

由于我们生成的类是不可变的并且永远不会被修改,因此hashCode结果将始终保持不变,并且在对象实例化期间只能计算一次。

如果你像这样注解你的类:

@Value.Immutable(prehash = true)
public abstract class Person {
    abstract String getName();
    abstract Integer getAge();
}

检查生成的类时,您可以看到hashCode值现在已预先计算并存储在一个字段中:

@Generated({"Immutables.generator", "Person"})
public final class ImmutablePerson extends Person {
    private final String name;
    private final Integer age;
    private final int hashCode;
    private ImmutablePerson(String name, Integer age) {
        this.name = name;
        this.age = age;
        this.hashCode = computeHashCode();
    }
    // generated methods
 
    @Override
    public int hashCode() {
        return hashCode;
    }
}

hashCode()方法返回构造对象时生成的预计算hashCode