グアバマルチセットガイド

  • link:/category/guava/ [グアバ]

1. 概要

このチュートリアルでは、https://www.baeldung.com/category/guava/ [Guava]コレクション– _Multiset_の1つを調べます。 _java.util.Set_と同様に、順序を保証することなく、アイテムを効率的に保管および取得できます。
ただし、_Set_とは異なり、含まれる各一意の要素の数を追跡することにより、同じ要素の*複数の出現*を許可します。

2. メーベン依存

まず、https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22com.google.guava%22%20AND%20a%3A%22guava%22 [_guava_依存関係]を追加しましょう。
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.1-jre</version>
</dependency>

3. _Multiset_の使用

異なる本の複数のコピーがある書店を考えてみましょう。 コピーの追加、コピーの数の取得、販売された1つのコピーの削除などの操作を実行できます。 * _Set_は同じ要素の複数の出現を許可しないため、この要件を処理できません。*
*本のタイトルのコピーを追加*して始めましょう。 _Multiset_は、タイトルが存在することを返し、正しいcount __:__を提供する必要があります
Multiset<String> bookStore = HashMultiset.create();
bookStore.add("Potter");
bookStore.add("Potter");
bookStore.add("Potter");

assertThat(bookStore.contains("Potter")).isTrue();
assertThat(bookStore.count("Potter")).isEqualTo(3);
1つのコピーを削除しましょう。 カウントはそれに応じて更新されると予想されます。
bookStore.remove("Potter");
assertThat(bookStore.contains("Potter")).isTrue();
assertThat(bookStore.count("Potter")).isEqualTo(2);
そして実際には、さまざまな追加操作を実行する代わりに、*カウントを設定するだけです*。
bookStore.setCount("Potter", 50);
assertThat(bookStore.count("Potter")).isEqualTo(50);
_Multiset_は、_count_値を検証します。 負に設定すると、_IllegalArgumentException_がスローされます。
assertThatThrownBy(() -> bookStore.setCount("Potter", -1))
  .isInstanceOf(IllegalArgumentException.class);

4. _Map_との比較

_Multiset_へのアクセスなしで、_java.util.Map:_を使用して独自のロジックを実装することにより、上記のすべての操作を実現できます。
Map<String, Integer> bookStore = new HashMap<>();
// adding 3 copies
bookStore.put("Potter", 3);

assertThat(bookStore.containsKey("Potter")).isTrue();
assertThat(bookStore.get("Potter")).isEqualTo(3);

// removing 1 copy
bookStore.put("Potter", 2);
assertThat(bookStore.get("Potter")).isEqualTo(2);
_Map_を使用してコピーを追加または削除する場合、現在のカウントを記憶し、それに応じて調整する必要があります。 また、呼び出しロジックに毎回このロジックを実装するか、この目的のために独自のライブラリを構築する必要があります。 また、コードは_value_引数を制御する必要があります。 注意しないと、両方の値が無効であっても、値を_null_または負に簡単に設定できます。
bookStore.put("Potter", null);
assertThat(bookStore.containsKey("Potter")).isTrue();

bookStore.put("Potter", -1);
assertThat(bookStore.containsKey("Potter")).isTrue();
ご覧のとおり、_Map_の代わりに_Multiset_を使用する方がはるかに便利です。

5. 並行性

並行環境で_Multiset_を使用する場合、スレッドセーフな_Multiset_実装である_ConcurrentHashMultiset_を使用できます。
ただし、スレッドセーフであっても一貫性は保証されません。 _add_または_remove_メソッドを使用すると、マルチスレッド環境でうまく機能しますが、*複数のスレッドが_setCount_メソッドを呼び出した場合はどうなりますか?_ _ *
_setCount_メソッドを使用する場合、*最終結果はスレッド間での実行順序*に依存しますが、これは必ずしも予測できません。 __add ___and _remove_メソッドはインクリメンタルであり、_ConcurrentHashMultiset_はそれらの動作を保護できます。 *カウントを直接設定することは増分ではないため、同時に使用すると予期しない結果が生じる可能性があります。*
ただし、現在の値が渡された引数と一致する場合にのみカウントを更新する_setCount_メソッドには別のフレーバーがあります。 このメソッドは、操作が成功するとtrueを返します。楽観的ロックの形式です。
Multiset<String> bookStore = HashMultiset.create();
// updates the count to 2 if current count is 0
assertThat(bookStore.setCount("Potter", 0, 2)).isTrue();
// updates the count to 5 if the current value is 50
assertThat(bookStore.setCount("Potter", 50, 5)).isFalse();
並行コードで_setCount_メソッドを使用する場合、一貫性を保証するために上記のバージョンを使用する必要があります。 カウントの変更に失敗した場合、マルチスレッドクライアントは再試行を実行できます。

6. 結論

この短いチュートリアルでは、_Multiset、_をいつどのように使用するかを説明し、標準の_Map_と比較し、コンカレントアプリケーションで最適に使用する方法を検討しました。
いつものように、例のソースコードはhttps://github.com/eugenp/tutorials/tree/master/guava-collections-set[GitHubで]にあります。