Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
Queue 是用于在处理之前保留元素的集合。除了基本的 Collection 操作外,队列还提供额外的插入,移除和检查操作。接下来是 Queue 接口。
public interface Queue<E> extends Collection<E> {
E element();
boolean offer(E e);
E peek();
E poll();
E remove();
}
每个 Queue 方法以两种形式存在:(1)如果操作失败,则抛出异常;(2)另一个如果操作失败,则返回特殊值(null 或 false,具体取决于操作)。接口的常规结构在 下表 中说明。
| 操作类型 | 抛出异常 | 返回特殊值 |
|---|---|---|
| 插入 | add(e) |
offer(e) |
| 移除 | remove() |
poll() |
| 检查 | element() |
peek() |
队列通常(但不一定)以 FIFO(先进先出)方式对元素进行排序。例外情况包括优先级队列,优先级队列根据元素的值对元素进行排序 有关详细信息,请参见 Object Ordering 部分。无论使用什么排序,队列的头部是通过调用 remove 或 poll 来移除的元素。在 FIFO 队列中,所有新元素都插入队列的尾部。其他类型的队列可能使用不同的放置规则。每个 Queue 实现都必须指定其排序属性。
Queue 实现可以限制它所拥有的元素数量;这样的队列被称为 bounded (有界的)。java.util.concurrent 中的某些 Queue 实现是有界的,但 java.util 中的实现不是。
add 方法,Queue 继承自 Collection,插入一个元素,除非它违反了队列的容量限制,在这种情况下它会抛出 IllegalStateException。offer 方法仅适用于有界队列,与 add 的区别仅在于它通过返回 false 来表示无法插入元素。
remove 和 poll 方法都移除并返回队列的头部。确切地移除哪个元素由队列的排序策略决定。仅当队列为空时,remove 和 poll 方法的行为才有所不同。在这些情况下,remove 抛出 NoSuchElementException,而 poll 返回 null。
element 和 peek 方法返回但不移除队列的头部。它们的区别与 remove 和 poll 完全相同:如果队列为空,element 会抛出 NoSuchElementException,而 peek 返回 null。
Queue 实现通常不允许插入 null 元素。LinkedList 实现是一个例外,它被改进以实现 Queue。由于历史原因,它允许 null 元素,但你应该避免利用这一点,因为 null 被 poll 和 peek 方法用作特殊返回值。
队列实现通常不定义 equals 和 hashCode 方法的基于元素的版本,而是从 Object 继承基于身份的版本。
Queue 接口未定义阻塞队列方法,这在并发编程中很常见。这些等待元素出现或空间可用的方法在接口 java.util.concurrent.BlockingQueue 中定义,继承 Queue。
在以下示例程序中,队列用于实现倒数计时器。队列预先加载了从命令行上指定的数字到 0 的所有整数值,按降序排列。然后,从队列中移除值并以一秒的间隔打印。该程序是人为的,因为在不使用队列的情况下执行相同的操作会更自然,但它说明了在后续处理之前使用队列来存储元素。
import java.util.*;
public class Countdown {
public static void main(String[] args) throws InterruptedException {
int time = Integer.parseInt(args[0]);
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = time; i >= 0; i--)
queue.add(i);
while (!queue.isEmpty()) {
System.out.println(queue.remove());
Thread.sleep(1000);
}
}
}
在以下示例中,优先级队列用于对元素集合进行排序。同样,这个程序是人为的,因为没有理由使用它来支持 Collections 中提供的 sort 方法,但它说明了优先级队列的行为。
static <E> List<E> heapSort(Collection<E> c) {
Queue<E> queue = new PriorityQueue<E>(c);
List<E> result = new ArrayList<E>();
while (!queue.isEmpty())
result.add(queue.remove());
return result;
}