1前書き

この記事では、http://immutables.github.io/[Immutables]ライブラリを使用する方法を説明します。

イミュータブルは、シリアライズ可能およびカスタマイズ可能なイミュータブルオブジェクトを生成および操作するためのアノテーションおよびアノテーションプロセッサから構成されています。

2. Mavenの依存関係

プロジェクトでImmutablesを使用するには、

pom.xml

ファイルの

dependencies

セクションに次の依存関係を追加する必要があります。

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

このアーティファクトは実行時には必要ないので、

provided

スコープを指定することをお勧めします。

このライブラリの最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22value%22%20org.immutables[ここ]にあります。


3不変物

ライブラリは抽象型から不変オブジェクトを生成します。


Interface



Class



Annotation

これを達成するための鍵は

@Value.Immutable

アノテーションの適切な使用です。

注釈付き型の不変バージョンを生成し、その名前の前に

Immutable

キーワード

を付けます。



X

」という名前の不変バージョンのクラスを生成しようとすると、「不変バージョン」というクラスが生成されます。

そして簡単な注意 – Immutablesはアノテーション処理を利用するので、IDEでアノテーション処理を有効にすることを忘れないでください。


3.1.

Abstract Classes

および

Interfaces




@Value.Immutable

を使用する

生成されるフィールドを表す2つの

abstract

アクセサメソッドからなる単純な

abstract

クラス

Person

を作成し、次に

@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

}

生成されたクラスは、実装された

toString



hashcode



equals

メソッドとstepbuilder

ImmutablePerson.Builder

が付属しています。

生成されたコンストラクタが

private

アクセス権を持っていることに注意してください。


ImmutablePerson

クラスのインスタンスを構築するには、

Person

オブジェクトから

ImmutablePerson

コピーを作成できるビルダーまたは静的メソッド

ImmutablePerson.copyOf、

を使用する必要があります。

ビルダーを使用してインスタンスを構築したい場合は、単純にコーディングできます

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

生成されたクラスは不変であるため、変更できません。既存のオブジェクトを変更したい場合は、元のオブジェクトを変更しないで、変更したフィールドを使用して新しいインスタンスを作成する「

withX

」メソッドの1つを使用できます。


johnの年齢を更新し、新しい

john43__オブジェクトを作成しましょう。

ImmutablePerson john43 = john.withAge(43);

そのような場合、以下の主張が成り立つでしょう。

assertThat(john).isNotSameAs(john43);

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


4追加のユーティリティ

そのようなクラス生成は、それをカスタマイズできなければあまり役に立ちません。不変ライブラリには、

@ Value.Immutable

の出力をカスタマイズするために使用できる一連の追加の注釈が付属しています。それらすべてを見るには、Immutablesのhttp://immutables.github.io/immutable.html[文書]を参照してください。


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

アノテーションは、オブジェクトのインスタンスに格納されるプロパティにアノテーションを付けるために使用できますが、

equals



hashCode

、および

toString

の実装では無視されます。

あなたがこのようにあなたのクラスに注釈をつけるならば:

@Value.Immutable
public abstract class Person {

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

    @Value.Auxiliary
    abstract String getAuxiliaryField();

}


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.

@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

を返します。


5結論

このクイックチュートリアルでは、http://immutables.github.io/[Immutables]ライブラリの基本的な動作を説明しました。

この記事のすべてのソースコードと単体テストはhttps://github.com/eugenp/tutorials/tree/master/immutables[GitHub repository]にあります。