Introduction to Immutables – 不动产简介

最后修改: 2016年 7月 31日

1. Introduction

1.介绍

In this article, we will be showing how to work with the Immutables library.

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

The library consists of annotations and annotation processors for generating and working with serializable and customizable immutable objects.

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

2. Maven Dependencies

2.Maven的依赖性

In order to use Immutables in your project, you need to add the following dependency to the dependencies section of your pom.xml file:

为了在你的项目中使用Immutables,你需要在你的pom.xml文件的dependencies部分添加以下依赖性。

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

As this artifact is not required during runtime, so it’s advisable to specify the provided scope.

由于这个工件在运行时不需要,所以建议指定provided范围。

The newest version of the library can be found here.

最新版本的库可以在这里找到。

3. Immutables

3.不变的东西

The library generates immutable objects from abstract types: Interface, Class, Annotation.

该库从抽象类型生成不可变的对象。Interface, Class, Annotation

The key to achieving this is the proper use of @Value.Immutable annotation. It generates an immutable version of an annotated type and prefixes its name with the Immutable keyword.

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

If we try to generate an immutable version of class named “X“, it will generate a class named “ImmutableX”. Generated classes are not recursively-immutable, so it’s good to keep that in mind.

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

And a quick note – because Immutables utilizes annotation processing, you need to remember to enable annotation processing in your IDE.

还有一个简单的说明–因为Immutables利用了注释处理,你需要记得在你的IDE中启用注释处理。

3.1. Using @Value.Immutable With Abstract Classes and Interfaces

3.1.使用@Value.Immutable的抽象类和接口

Let’s create a simple abstract class Person consisting of two abstract accessor methods representing the to-be-generated fields, and then annotate the class with the @Value.Immutable annotation:

让我们创建一个简单的抽象Person,由两个抽象访问器方法组成,代表将要生成的字段,然后用@Value.Immutable注解为该类。

@Value.Immutable
public abstract class Person {

    abstract String getName();
    abstract Integer getAge();

}

After annotation processing is done, we can find a ready-to-use, newly-generated ImmutablePerson class in a target/generated-sources directory:

注释处理完成后,我们可以在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

}

The generated class comes with implemented toString, hashcode, equals methods and with a stepbuilder ImmutablePerson.Builder. Notice that the generated constructor has private access.

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

In order to construct an instance of ImmutablePerson class, we need to use the builder or static method ImmutablePerson.copyOf, which can create an ImmutablePerson copy from a Person object.

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

If we want to construct an instance using the builder, we can simply code:

如果我们想用构建器来构建一个实例,我们可以简单地编码。

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

Generated classes are immutable which means they can’t be modified. If you want to modify an already existing object, you can use one of the “withX” methods, which do not modify an original object, but create a new instance with a modified field.

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

Let’s update john’s age and create a new john43 object:

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

ImmutablePerson john43 = john.withAge(43);

In such a case the following assertions will be true:

在这种情况下,以下断言将是真实的。

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

4. Additional Utilities

4.其他实用程序

Such class generation would not be very useful without being able to customize it. Immutables library comes with a set of additional annotations that can be used for customizing @Value.Immutable‘s output. To see all of them, please refer to Immutables’ documentation.

如果不能够对其进行定制,这样的类生成就不会很有用。Immutables库带有一组额外的注释,可用于定制@Value.Immutable的输出。要查看所有这些注释,请参考Immutables的文档

4.1. The @Value.Parameter Annotation

4.1.@Value.Parameter 注释

The @Value.Parameter annotation can be used for specifying fields, for which constructor method should be generated.

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

If you annotate your class like this:

如果你像这样注释你的类。

@Value.Immutable
public abstract class Person {

    @Value.Parameter
    abstract String getName();

    @Value.Parameter
    abstract Integer getAge();
}

It will be possible to instantiate it in the following way:

将有可能以下列方式将其实例化。

ImmutablePerson.of("John", 42);

4.2. The @Value.Default Annotation

4.2.@Value.Default 注释

The @Value.Default annotation allows you to specify a default value that should be used when an initial value is not provided. In order to do this, you need to create a non-abstract accessor method returning a fixed value and annotate it with @Value.Default:

@Value.Default 注解允许你指定一个默认值,当没有提供初始值时,应该使用该值。为了做到这一点,你需要创建一个返回固定值的非抽象访问器方法,并用@Value.Default来注释它。

@Value.Immutable
public abstract class Person {

    abstract String getName();

    @Value.Default
    Integer getAge() {
        return 42;
    }
}

The following assertion will be true:

下面的断言将是真的。

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

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

4.3. The @Value.Auxiliary Annotation

4.3.@Value.Auxiliary 注释

The @Value.Auxiliary annotation can be used for annotating a property that will be stored in an object’s instance, but will be ignored by equals, hashCode and toString implementations.

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

If you annotate your class like this:

如果你像这样注释你的类。

@Value.Immutable
public abstract class Person {

    abstract String getName();
    abstract Integer getAge();

    @Value.Auxiliary
    abstract String getAuxiliaryField();

}

The following assertions will be true when using the auxiliary field:

当使用auxiliary字段时,以下断言将为真。

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. The @Value.Immutable(Prehash = True) Annotation

4.4.@Value.Immutable(Prehash = True) 注释

Since our generated classes are immutable and can never get modified, hashCode results will always remain the same and can be computed only once during the object’s instantiation.

由于我们生成的类是不可变的,永远不会被修改,hashCode的结果将永远保持不变,在对象的实例化过程中只能被计算一次。

If you annotate your class like this:

如果你像这样注释你的类。

@Value.Immutable(prehash = true)
public abstract class Person {

    abstract String getName();
    abstract Integer getAge();

}

When inspecting the generated class, you can see that hashcode value is now precomputed and stored in a field:

在检查生成的类时,你可以看到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;
    }
}

The hashCode() method returns a precomputed hashcode generated when the object was constructed.

hashCode()方法返回一个在构建对象时生成的预计算的hashcode

5. Conclusion

5.结论

In this quick tutorial we showed the basic workings of the Immutables library.

在这个快速教程中,我们展示了Immutables库的基本工作原理。

All source code and unit tests in the article can be found in the GitHub repository.

文章中的所有源代码和单元测试都可以在GitHub资源库中找到。