インタフェースQueueの実装クラス

Revised: May/10th/2008; Since: Aug./07th/2005

Queueインタフェース

インタフェースjava.util.Queue(API仕様)は、J2SE 5.0で追加されました。インタフェースCollectionを直接継承し、Set, Listと並んで、コレクション・フレームワークの基底となるインタフェースです。

実装クラスが表すキューは、FIFO (先入れ先出しの待ち行列)か LIFO (後入れ先出しのスタック)を表すことが多いでしょう。概念的には、特殊なListに似ています。

Collectionに追加して宣言するメソッドは次のメソッドです。挿入/削除/検査に対して、2つづつメソッドが用意されています。

例外をスローする 特殊な値を返す
挿入 add(e) offer(e)
削除 remove() poll()
検査 element() peek()

挿入時に対して空きがない場合、add()IllegalStateExceptionがスローされ、offer()falseを返します。削除と検査の場合に要素が存在しない場合は、remove()element()NoSuchElementExceptionがスローされ、poll()peek()nullを返します。

BlockingQueueインタフェース

待ち行列のブロッキングについては、Queueのサブインタフェースjava.util.concurrent.BlockingQueue(API仕様)でサポートされています。

例外のスロー 特殊な値 ブロック タイムアウト
挿入 add(e) offer(e) put(e) offer(e, time, unit)
削除 remove() poll() take() poll(time, unit)
検査 element() peek() 適用外 適用外

要素の追加と削除に対して、put()take()では、処理可能になるまで(空き領域が生じるか、処理対象の要素が追加されるまで)待機します。一方、offer()poll()では、タイムアウト値を指定します。待機時間がタイムアウト値を超えると、offerの場合はfalseを、poll()の場合はnullを返します。

例えば、実装クラスの一つjava.util.concurrent.ArrayBlockingQueueの場合、固定長のFIFOキュー(先入れ先出し待ち行列)が生成され、put()するときにキューが埋まっている場合は、空きが生じるまで待たされます。take()するときにキューが空の場合も、要素が追加されるまで待たされます。

Dequeインタフェース

Java SE 6では、Queueのサブインタフェースとして、インタフェースDeque(API仕様)が追加されました。

Queueに対して、両端での追加/削除をサポートするように拡張されています。Dequeは、"Double Ended Queue"の省略で、「デック」と発音するそうです(キューから要素を取り出す「デキュー」ではありません)。

両端を操作するメソッドは次の通りです。

インタフェースDequeの基本操作メソッド
最初の要素 (先頭) 最後の要素 (末尾)
例外をスローする 特殊な値 例外をスローする 特殊な値
挿入 addFirst(e) offerFirst(e) addLast(e) offerLast(e)
削除 removeFirst() pollFirst() removeLast() pollLast()
検査 getFirst() peekFirst() getLast() peekLast()

Queueインタフェースで定義されているメソッドはFIFO(先入れ先出し)キューを実装するために、最後尾に追加し、先頭から取り出すように動作します。一方、LIFO(後入れ先出し)キューはStackで実装されており、そちらでは先頭に追加し、先頭から取り出します。

上記のDequeメソッドの中で、Queueメソッドと対応するのは次の通りです。LinkedListは両方のインタフェースを実装しているので、全てのメソッドが使えます。

Queueメソッドと等価なDequeメソッド
例外をスローする 特殊な値を返す
Queueメソッド等価なDequeメソッドQueueメソッド等価なDequeメソッド
挿入 add(e) addLast(e) offer(e) offerLast(e)
削除 remove() removeFirst() poll() pollFirst()
検査 element() getFirst() peek() peekFirst()

同様に、Stackメソッドと対応するのは次の通りです。Stackメソッドはコレクション・フレームワークよりも古いクラスであり、要素数が条件を満たしていない場合は、例外をスローするメソッドと、特殊な値を返すメソッドが混じっています。

Stackメソッドと等価なDequeメソッド
例外をスローする 特殊な値を返す
Stackメソッド 等価なDequeメソッド Stackメソッド 等価なDequeメソッド
挿入 push(e) addFirst(e) N/A offerFirst(e)
削除 pop() removeFirst() N/A pollFirst()
検査 N/A getFirst() peek() peekFirst()

Queueの利用

基本的なメソッド

次の例では、Queueのメソッドoffer()(要素を最後尾に追加), peek()(先頭の要素の取り出し), poll()(先頭の要素の参照)を使っています。

import java.util.Queue;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.concurrent.ArrayBlockingQueue;

class TestQueue {
	public static void main(String[] args) {
		Queue<Integer> queue = new LinkedList<Integer>();
		queue = setQueue(queue);
		consumeQueue(queue);

		Queue<Integer> queue2 = new ArrayBlockingQueue<Integer>(3);
		queue = setQueue(queue2);
		consumeQueue(queue2);

		Queue<Integer> queue3 = new ArrayDeque<Integer>();
		queue = setQueue(queue3);
		consumeQueue(queue3);
	}

	static Queue<Integer> setQueue(Queue<Integer> queue) {
		System.out.println("---- " + queue.getClass().getName() + " ----");
		for ( int i = 0;i < 6;i++ ) {
			System.out.println("offer(): " + queue.offer(i) + ": " + queue);
		}
		return queue;
	}
	
	static <E> void consumeQueue(Queue<E> queue) {
		for (int i = 0; i < 9; i++) {
			System.out.println("peek(): " + queue.peek() + ": " + queue);
			System.out.println("poll(): " + queue.poll());
		}
	}

}

次の実行結果を見ると、offer()は最後尾に要素を追加し、poll()は先頭から要素を削除していることが分かります。先に入れたものが先に取り出されているので、FIFOキューを実装していることになります。

また、空のキューに対するpoll()peek()nullを返すことが分かります。remove()element()に変更すると、例外がスローされます。キューのサイズを指定しているArrayBlockingQueueでは、サイズを超えたoffer()falseを返しています。add()に変更すると、例外がスローされます。

C:\java>javac TestQueue.java

C:\java>java TestQueue
---- java.util.LinkedList ----
offer(): true: [0]
offer(): true: [0, 1]
offer(): true: [0, 1, 2]
offer(): true: [0, 1, 2, 3]
offer(): true: [0, 1, 2, 3, 4]
offer(): true: [0, 1, 2, 3, 4, 5]
peek(): 0: [0, 1, 2, 3, 4, 5]
poll(): 0
peek(): 1: [1, 2, 3, 4, 5]
poll(): 1
peek(): 2: [2, 3, 4, 5]
poll(): 2
peek(): 3: [3, 4, 5]
poll(): 3
peek(): 4: [4, 5]
poll(): 4
peek(): 5: [5]
poll(): 5
peek(): null: []
poll(): null
peek(): null: []
poll(): null
peek(): null: []
poll(): null
---- java.util.concurrent.ArrayBlockingQueue ----
offer(): true: [0]
offer(): true: [0, 1]
offer(): true: [0, 1, 2]
offer(): false: [0, 1, 2]
offer(): false: [0, 1, 2]
offer(): false: [0, 1, 2]
peek(): 0: [0, 1, 2]
poll(): 0
peek(): 1: [1, 2]
poll(): 1
peek(): 2: [2]
poll(): 2
peek(): null: []
poll(): null
peek(): null: []
poll(): null
peek(): null: []
poll(): null
peek(): null: []
poll(): null
peek(): null: []
poll(): null
peek(): null: []
poll(): null
---- java.util.ArrayDeque ----
offer(): true: [0]
offer(): true: [0, 1]
offer(): true: [0, 1, 2]
offer(): true: [0, 1, 2, 3]
offer(): true: [0, 1, 2, 3, 4]
offer(): true: [0, 1, 2, 3, 4, 5]
peek(): 0: [0, 1, 2, 3, 4, 5]
poll(): 0
peek(): 1: [1, 2, 3, 4, 5]
poll(): 1
peek(): 2: [2, 3, 4, 5]
poll(): 2
peek(): 3: [3, 4, 5]
poll(): 3
peek(): 4: [4, 5]
poll(): 4
peek(): 5: [5]
poll(): 5
peek(): null: []
poll(): null
peek(): null: []
poll(): null
peek(): null: []
poll(): null

C:\java>

Dequeの例

次の例は、インタフェースDequeの実装クラスの例です。

LIFOキュー(スタック)にするために、先頭に追加して先頭から取得しています(末尾に追加して末尾から取得しても同じです)。

import java.util.Deque;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.concurrent.ArrayBlockingQueue;

class TestDeque {
	public static void main(String[] args) {
		Deque<Integer> queue = new LinkedList<Integer>();
		queue = setQueue(queue);
		consumeQueue(queue);
		
		Deque<Integer> queue2 = new ArrayDeque<Integer>();
		queue = setQueue(queue2);
		consumeQueue(queue2);
	}

	static Deque<Integer> setQueue(Deque<Integer> queue) {
		System.out.println("---- " + queue.getClass().getName() + " ----");
		for ( int i = 0;i < 6;i++ ) {
			System.out.println("offerFirst(): " + queue.offerFirst(i) + ": " + queue);
		}
		return queue;
	}
	
	// 型変数Eを宣言して引数で使っているが、
	// ブロック内で使っていないので意味がない
	static <E> void consumeQueue(Deque<E> queue) {
		for (int i = 0; i < 9; i++) {
			System.out.println("peekFirst(): " + queue.peekFirst() + ": " + queue);
			System.out.println("pollFirst(): " + queue.pollFirst());
		}
        System.out.println();
	}
}
D:\java>javac TestDeque.java

D:\java>java TestDeque
---- java.util.LinkedList ----
offerFirst(): true: [0]
offerFirst(): true: [1, 0]
offerFirst(): true: [2, 1, 0]
offerFirst(): true: [3, 2, 1, 0]
offerFirst(): true: [4, 3, 2, 1, 0]
offerFirst(): true: [5, 4, 3, 2, 1, 0]
peekFirst(): 5: [5, 4, 3, 2, 1, 0]
pollFirst(): 5
peekFirst(): 4: [4, 3, 2, 1, 0]
pollFirst(): 4
peekFirst(): 3: [3, 2, 1, 0]
pollFirst(): 3
peekFirst(): 2: [2, 1, 0]
pollFirst(): 2
peekFirst(): 1: [1, 0]
pollFirst(): 1
peekFirst(): 0: [0]
pollFirst(): 0
peekFirst(): null: []
pollFirst(): null
peekFirst(): null: []
pollFirst(): null
peekFirst(): null: []
pollFirst(): null
---- java.util.ArrayDeque ----
offerFirst(): true: [0]
offerFirst(): true: [1, 0]
offerFirst(): true: [2, 1, 0]
offerFirst(): true: [3, 2, 1, 0]
offerFirst(): true: [4, 3, 2, 1, 0]
offerFirst(): true: [5, 4, 3, 2, 1, 0]
peekFirst(): 5: [5, 4, 3, 2, 1, 0]
pollFirst(): 5
peekFirst(): 4: [4, 3, 2, 1, 0]
pollFirst(): 4
peekFirst(): 3: [3, 2, 1, 0]
pollFirst(): 3
peekFirst(): 2: [2, 1, 0]
pollFirst(): 2
peekFirst(): 1: [1, 0]
pollFirst(): 1
peekFirst(): 0: [0]
pollFirst(): 0
peekFirst(): null: []
pollFirst(): null
peekFirst(): null: []
pollFirst(): null
peekFirst(): null: []
pollFirst(): null

D:\java>


Copyright © 2005-2008 SUGAI, Manabu. All Rights Reserved.