グアバへのガイドMinMaxPriorityQueueおよびEvictingQueue

Guava MinMaxPriorityQueueおよびEvictingQueueのガイド

1. Overview

この記事では、GuavaライブラリのEvictingQueue,およびMinMaxPriorityQueueコンストラクトについて説明します。 EvictingQueueは、循環バッファの概念の実装です。 MinMaxPriorityQueueは、提供されたComparator.を使用して、最小要素と最大要素へのアクセスを提供します。

2. EvictingQueue

構築から始めましょう–キューのインスタンスを構築するとき、引数として最大キューサイズを指定する必要があります。

EvictingQueuethe queue is full, it automatically evicts an element from its headに新しいアイテムを追加したい場合。

標準のキューの動作と比較すると、要素を完全なキューに追加してもブロックされませんが、ヘッド要素が削除され、新しいアイテムがテールに追加されます。

EvictingQueueは、追加のみの方法で要素を挿入するリングとして想像できます。 新しい要素を追加する位置に要素がある場合、指定された位置にある既存の要素をオーバーライドします。

最大サイズが10のEvictingQueueのインスタンスを作成しましょう。 次に、10個の要素を追加します。

Queue evictingQueue = EvictingQueue.create(10);

IntStream.range(0, 10)
  .forEach(evictingQueue::add);

assertThat(evictingQueue)
  .containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

標準のキュー実装がある場合、新しいアイテムを完全なキューに追加するとプロデューサーがブロックされます。

これは、EvictingQueueの実装には当てはまりません。 新しい要素を追加すると、そこから頭が削除され、新しい要素が尾に追加されます。

evictingQueue.add(100);

assertThat(evictingQueue)
  .containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 100);

EvictingQueueを循環バッファとして使用することにより、非常に効率的な並行プログラムを作成できます。

3. MinMaxPriorityQueue

MinMaxPriorityQueueは、最小要素と最大要素への常時アクセスを提供します。

最小の要素を取得するには、peekFirst()メソッドを呼び出す必要があります。 最大の要素を取得するには、peekLast()メソッドを呼び出すことができます。 これらはキューから要素を削除せず、それを取得するだけであることに注意してください。

要素の順序付けは、このキューのコンストラクターに渡す必要があるComparatorによって行われます。

整数型のvalueフィールドを持つCustomClassクラスがあるとしましょう。

class CustomClass {
    private Integer value;

    // standard constructor, getters and setters
}

intタイプでコンパレータを使用するMinMaxPriorityQueueを作成しましょう。 次に、CustomClassタイプの10個のオブジェクトをキューに追加します。

MinMaxPriorityQueue queue = MinMaxPriorityQueue
  .orderedBy(Comparator.comparing(CustomClass::getValue))
  .maximumSize(10)
  .create();

IntStream
  .iterate(10, i -> i - 1)
  .limit(10)
  .forEach(i -> queue.add(new CustomClass(i)));

MinMaxPriorityQueueと渡されたComparator,の特性により、キューの先頭の要素は1に等しく、キューの末尾の要素は10に等しくなります。

assertThat(
  queue.peekFirst().getValue()).isEqualTo(1);
assertThat(
  queue.peekLast().getValue()).isEqualTo(10);

キューの容量は10であり、10個の要素を追加したため、キューはいっぱいです。 新しい要素を追加すると、キューの最後の要素が削除されます。 valueが-1に等しいCustomClassを追加しましょう。

queue.add(new CustomClass(-1));

そのアクションの後、キューの最後の要素が削除され、その末尾の新しいアイテムは9になります。 これは、キューの作成時に渡されたComparatorに応じた新しい最小要素であるため、新しいヘッドは-1になります。

assertThat(
  queue.peekFirst().getValue()).isEqualTo(-1);
assertThat(
  queue.peekLast().getValue()).isEqualTo(9);

MinMaxPriorityQueue,in case the queue is full, adding an element that is greater than the currently greatest element will remove that same element – effectively ignoring it.の仕様による

100の数字を追加して、その操作の後にそのアイテムがキューにあるかどうかをテストしてみましょう。

queue.add(new CustomClass(100));
assertThat(queue.peekFirst().getValue())
  .isEqualTo(-1);
assertThat(queue.peekLast().getValue())
  .isEqualTo(9);

ご覧のとおり、キューの最初の要素はまだ-1に等しく、最後は9に等しくなっています。 したがって、整数を追加しても、キュー内の既に最大の要素よりも大きいため、無視されました。

4. 結論

この記事では、GuavaライブラリのEvictingQueueMinMaxPriorityQueueコンストラクトを確認しました。

非常に効率的なプログラムを実装するための循環バッファとしてEvictingQueueを使用する方法を見ました。

MinMaxPriorityQueueComparatorを組み合わせて使用​​し、最小要素と最大要素に常時アクセスできるようにしました。

新しい要素を追加すると、すでにキューにある要素が上書きされるため、提示された両方のキューの特性を覚えておくことが重要です。 これは、キュー全体に新しい要素を追加するとプロデューサースレッドがブロックされるか、例外がスローされる標準のキュー実装とは異なります。

これらすべての例とコードスニペットの実装は、GitHub projectにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。