1. 概要

Lombokライブラリは、データオブジェクトを単純化する優れた方法を提供します。 Project Lombok の重要な機能の1つは、 @Builderアノテーションです。これは、不変オブジェクトを作成するためのBuilderクラスを自動的に作成します。 ただし、オブジェクトにコレクションを設定すると、Lombokで生成された標準のBuilderクラスでは扱いにくい場合があります。

このチュートリアルでは、 @Singular アノテーションを確認します。これは、がデータオブジェクト内のコレクションの操作に役立ちます。これにより、グッドプラクティスも適用されます。見る。

2. ビルダーとコレクション

Builder クラスを使用すると、シンプルで流暢な構文で不変のデータオブジェクトを簡単に構築できます。 Lombokの@Builderアノテーションが付けられたクラスの例を見てみましょう。

@Getter
@Builder
public class Person {
    private final String givenName;
    private final String additionalName;
    private final String familyName;
    private final List<String> tags;
}

これで、ビルダーパターンを使用してPersonのインスタンスを作成できます。 ここで、tagsプロパティはListであることに注意してください。 さらに、標準のLombok @Builder は、非リストプロパティの場合と同様に、このプロパティを設定するメソッドを提供します。

Person person = Person.builder()
  .givenName("Aaron")
  .additionalName("A")
  .familyName("Aardvark")
  .tags(Arrays.asList("fictional","incidental"))
  .build();

これは実行可能ですが、かなり不器用な構文です。 上記のように、コレクションをインラインで作成できます。 または、事前に宣言することもできます。 いずれにせよ、それは私たちのオブジェクト作成の流れを壊します。 ここで、@Singularアノテーションが役立ちます。

2.1. @SingularアノテーションをListで使用する

別のListPersonオブジェクトに追加し、@Singularで注釈を付けましょう。 これにより、注釈が付けられているフィールドと注釈が付けられていないフィールドを並べて表示できます。 一般的なtagsプロパティに加えて、InterestsのリストをPersonに追加します。

@Singular private final List<String> interests;

これで、一度に1つずつ値のリストを作成できます。

Person person = Person.builder()
  .givenName("Aaron")
  .additionalName("A")
  .familyName("Aardvark")
  .interest("history")
  .interest("sport")
  .build();

Builderは、各要素を List に内部的に格納し、 build()を呼び出すときに適切なCollectionを作成します。

2.2. 他のコレクションタイプの操作

ここでは、@Singularjava.util.List で動作することを示しましたが、は他のJavaコレクションクラスにも適用できます。 Personにさらにメンバーを追加しましょう。

@Singular private final Set<String> skills;
@Singular private final Map<String, LocalDate> awards;

Set は、 Builder に関する限り、Listと同じように動作します。要素を1つずつ追加できます。

Person person = Person.builder()
  .givenName("Aaron")
  .skill("singing")
  .skill("dancing")
  .build();

Set は重複をサポートしていないため、同じ要素を複数回追加しても複数の要素が作成されないことに注意する必要があります。 Builderはこの状況を寛大に処理します。 要素を複数回追加できますが、作成されたSetには要素が1回だけ出現します。

Map の扱いは少し異なり、 Builder は、適切なタイプのキーと値を受け取るメソッドを公開します。

Person person = Person.builder()
  .givenName("Aaron")
  .award("Singer of the Year", LocalDate.now().minusYears(5))
  .award("Best Dancer", LocalDate.now().minusYears(2))
  .build();

Set で見たように、ビルダーは重複する Map キーに寛容であり、同じキーが複数回割り当てられている場合は最後の値を使用します。

3. @Singularメソッドの命名

これまでのところ、 @Singular アノテーションでは、注意を引くことなく1ビットの魔法に依存してきました。 Builder 自体は、複数形を使用してコレクション全体を一度に割り当てる方法を提供します。たとえば、「Awards」などです。 @Singularアノテーションによって追加された追加のメソッドは、「Award」などの特異な形式を使用します。

Lombokは、英語の単純な複数形の単語を認識できるほど賢く、規則的なパターンに従います。 これまでに使用したすべての例では、最後の「s」を削除するだけです。

また、「es」で終わる単語の場合、最後の2文字を削除することもわかります。 たとえば、「草」は「草」の単数形であり、「ブドウ」ではなく「ブドウ」が「ブドウ」の単数形であることを知っています。 ただし、場合によっては、支援を提供する必要があります。

魚と海草を含む海の簡単なモデルを作成してみましょう。

@Getter
@Builder
public class Sea {
    @Singular private final List<String> grasses;
    @Singular private final List<String> fish;
}

ロンボクは「草」という言葉を扱うことができますが、「魚」で失われます。 英語では、単数形と複数形は同じですが、奇妙なことに十分です。 このコードはコンパイルされず、エラーが発生します。

Can't singularize this name; please specify the singular explicitly (i.e. @Singular("sheep"))

アノテーションに値を追加して、単一のメソッド名として使用することで、物事を整理できます。

@Singular("oneFish") private final List<String> fish;

これで、コードをコンパイルしてBuilderを使用できます。

Sea sea = Sea.builder()
  .grass("Dulse")
  .grass("Kelp")
  .oneFish("Cod")
  .oneFish("Mackerel")
  .build();

この場合、かなり工夫された oneFish()を選択しましたが、同じメソッドを、明確な複数形を持つ非標準の単語で使用できます。 たとえば、childrenListは、メソッド child()で提供できます。

4. 不変性

@Singular アノテーションが、ロンボクのコレクションを操作するのにどのように役立つかを見てきました。 利便性と表現力を提供するだけでなく、コードをクリーンに保つのにも役立ちます。

不変オブジェクトは、作成後に変更できないオブジェクトとして定義されます。 不変性は、たとえば、リアクティブアーキテクチャでは重要です。これにより、副作用がないことが保証されたメソッドにオブジェクトを渡すことができるためです。 Builderパターンは、不変性をサポートするために、POJOゲッターおよびセッターの代替として最も一般的に使用されます。

データオブジェクトにCollectionクラスが含まれている場合、不変性を少し滑らせるのは簡単です。 基本コレクションインターフェイス( List Set 、および Map )には、すべて可変および不変の実装があります。 標準のLombokビルダーに依存している場合、誤って可変コレクションを渡し、それを変更する可能性があります。

List<String> tags= new ArrayList();
tags.add("fictional");
tags.add("incidental");
Person person = Person.builder()
  .givenName("Aaron")
  .tags(tags)
  .build();
person.getTags().clear();
person.getTags().add("non-fictional");
person.getTags().add("important");

この簡単な例では、間違いを犯すためにかなりの努力をしなければなりませんでした。 たとえば、 Arrays.asList()を使用して変数 tags を作成した場合、不変のリストを無料で取得し、addを呼び出します。 ()または clear()は、UnsupportedOperationExceptionをスローします。

実際のコーディングでは、たとえば、コレクションがパラメーターとして渡された場合、エラーが発生する可能性が高くなります。 ただし、 @Singularを使用すると、build()を呼び出すときに、ベースコレクションインターフェイスを操作して不変のインスタンスを取得できることを知っておくとよいでしょう。

5. 結論

このチュートリアルでは、Lombok @Singular アノテーションが、 List Set 、およびMap[を操作する便利な方法を提供する方法を見てきました。 X160X]Builderパターンを使用したインターフェース。 Builderパターンは不変性をサポートしており、@Singularはこれに対するファーストクラスのサポートを提供します。

いつものように、完全なコード例はGitHubから入手できます。