1. 序章

この記事では、Immutablesライブラリの操作方法を紹介します。

ライブラリは、シリアル化およびカスタマイズ可能な不変オブジェクトを生成および操作するための注釈と注釈プロセッサで構成されています。

2. Mavenの依存関係

プロジェクトでImmutablesを使用するには、pom.xmlファイルのdependenciesセクションに次の依存関係を追加する必要があります。

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

このアーティファクトは実行時に必要ないため、提供スコープを指定することをお勧めします。

ライブラリの最新バージョンはここにあります。

3. 不変

ライブラリは、抽象型から不変オブジェクトを生成します: Interface Class Annotation

これを実現するための鍵は、 @Value.Immutableアノテーションを適切に使用することです。 注釈付きタイプの不変バージョンを生成し、その名前の前に不変キーワードを付けます。

「」という名前のクラスの不変バージョンを生成しようとすると、 バツ 「、という名前のクラスが生成されます 「ImmutableX」。 生成されたクラスは再帰的に不変ではないため、このことを覚えておくとよいでしょう。

また、簡単な注意– Immutablesは注釈処理を利用しているため、IDEで注釈処理を有効にすることを忘れないでください。

3.1. @Value.Immutable抽象クラスおよびインターフェースで使用する

生成されるフィールドを表す2つのabstractアクセサメソッドで構成される単純なabstractクラスPersonを作成し、クラスにアノテーションを付けましょう。 @ Value.Immutable アノテーション:

@Value.Immutable
public abstract class Person {

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

}

アノテーション処理が完了すると、すぐに使用できる新しく生成されたImmutablePersonクラスがtarget/generated-sourcesディレクトリに見つかります。

@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 メソッド、およびステップビルダーImmutablePerson.Builderが付属しています。 生成されたコンストラクターにはprivateアクセスがあることに注意してください。

ImmutablePerson クラスのインスタンスを構築するには、ビルダーまたは静的メソッド ImmutablePerson.copyOf、を使用する必要があります。これにより、ImmutablePersonコピーを[ X202X]Personオブジェクト。

ビルダーを使用してインスタンスを構築する場合は、次のようにコーディングするだけです。

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 アノテーションは、オブジェクトのインスタンスに格納されるプロパティにアノテーションを付けるために使用できますが、 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 の結果は常に同じままであり、オブジェクトのインスタンス化中に1回だけ計算できます。

このようにクラスに注釈を付ける場合:

@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. 結論

このクイックチュートリアルでは、Immutablesライブラリの基本的な動作を示しました。

この記事のすべてのソースコードと単体テストは、GitHubリポジトリにあります。