Guava MinMaxPriorityQueueおよびEvictingQueueのガイド
1. Overview
この記事では、GuavaライブラリのEvictingQueue,およびMinMaxPriorityQueueコンストラクトについて説明します。 EvictingQueueは、循環バッファの概念の実装です。 MinMaxPriorityQueueは、提供されたComparator.を使用して、最小要素と最大要素へのアクセスを提供します。
2. EvictingQueue
構築から始めましょう–キューのインスタンスを構築するとき、引数として最大キューサイズを指定する必要があります。
EvictingQueueとthe 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ライブラリのEvictingQueueとMinMaxPriorityQueueコンストラクトを確認しました。
非常に効率的なプログラムを実装するための循環バッファとしてEvictingQueueを使用する方法を見ました。
MinMaxPriorityQueueとComparatorを組み合わせて使用し、最小要素と最大要素に常時アクセスできるようにしました。
新しい要素を追加すると、すでにキューにある要素が上書きされるため、提示された両方のキューの特性を覚えておくことが重要です。 これは、キュー全体に新しい要素を追加するとプロデューサースレッドがブロックされるか、例外がスローされる標準のキュー実装とは異なります。
これらすべての例とコードスニペットの実装は、GitHub projectにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。