Java教程适用于JDK 8。本页面中描述的示例和实践不利用后续版本引入的改进,并且可能使用不再可用的技术。
有关Java SE 9和后续版本中更新的语言特性的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息,请参阅JDK版本说明。
一个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)的方式对元素进行排序。优先级队列是一种例外,它根据元素的值进行排序 - 详见对象排序部分)。无论使用什么排序方式,队列的头部元素是通过调用remove
或poll
方法来删除的。在FIFO队列中,所有新元素都插入到队列的尾部。其他类型的队列可能使用不同的插入规则。每个Queue
实现都必须指定其排序属性。
Queue
实现可以限制它所保存的元素数量;这种队列称为有界队列。一些java.util.concurrent
中的Queue
实现是有界的,但java.util
中的实现不是。
add
方法是Queue
从Collection
继承的,它插入一个元素,除非它违反了队列的容量限制,否则会抛出IllegalStateException
异常。offer
方法只用于有界队列,与add
方法的区别在于它通过返回false
来表示插入元素失败。
remove
和poll
方法都会移除并返回队列的头部元素。具体移除的是哪个元素是由队列的排序策略决定的。当队列为空时,remove
方法会抛出NoSuchElementException
异常,而poll
方法会返回null
。
element
和peek
方法返回队列的头部元素,但不会将其移除。它们与remove
和poll
的区别与之相同:如果队列为空,element
方法会抛出NoSuchElementException
异常,而peek
方法会返回null
。
Queue
实现通常不允许插入null
元素。但是,LinkedList
实现是一个例外,它被改造成实现Queue
接口,并允许插入null
元素,但你应该避免利用这一点,因为poll
和peek
方法会将null
作为特殊返回值。
Queue实现通常不定义基于元素的equals
和hashCode
方法,而是继承自Object
的基于身份的版本。
Queue
接口没有定义阻塞队列方法,这在并发编程中很常见。这些方法等待元素出现或可用空间,它们被定义在接口java.util.concurrent.BlockingQueue
中,该接口扩展了Queue
接口。
在下面的示例程序中,使用队列实现了一个倒计时器。队列会预先加载从命令行指定的数字到零的所有整数值,按照降序排列。然后,这些值会在一秒的时间间隔内从队列中移除并打印出来。这个程序是人为的,因为在没有使用队列的情况下做同样的事情更自然,但它展示了在后续处理之前使用队列存储元素的用法。
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> 堆排序(Collection<E> c) { Queue<E> 队列 = new PriorityQueue<E>(c); List<E> 结果 = new ArrayList<E>(); while (!队列.isEmpty()) 结果.add(队列.remove()); return 结果; }