Java 集合:Queue 接口(队列)

Java 中的 Queue 接口(全类名:java.util.Queue)是一种遵循 FIFO(First-In-First-Out,先进先出)规则的核心数据结构。其核心设计逻辑为:仅允许在队列的尾部(队尾)插入元素,同时仅允许在队列的头部(队首)移除元素 —— 这一特性与日常生活中“超市排队结账”的场景高度契合:先排队的人(先入队元素)优先结算离开(先出队),后续来人(新插入元素)则需在队尾依次等候。

20251003171253.png 

注意,Queue 接口是 Java 集合框架中 Collection 接口的子类型。与 List 类似,它也用于表示一个有序的对象序列,但两者的设计意图存在差异:Queue 更侧重于实现队列这种类具有明确存取规则的数据结构。

Queue 作为 Collection 接口的子类型,Queue 自然继承了 Collection 接口中定义的所有方法(如 add()、remove()、size() 等),因此具备集合框架的基本操作能力。

  

Queue 实现

由于 Queue 是一个接口,你需要实例化该接口的一个具体实现才能使用它。Queue 存在一下实现:

  • java.util.LinkedList  是 Queue 接口的常用实现类之一,同时也实现了 List 接口。它基于双向链表数据结构实现,因此支持队列的基本操作(如 add() 入队、poll() 出队等),还允许通过索引访问元素。由于链表的特性,LinkedList 在队列首尾进行插入 / 删除操作时效率较高(时间复杂度为 O (1)),但随机访问元素的效率较低(时间复杂度为 O (n))。它适用于需要频繁在队列两端操作,且对元素顺序有严格 FIFO 要求的场景。

  • java.util.PriorityQueue  是另一种常见的 Queue 实现,其核心特点是不遵循严格的 FIFO 规则,而是根据元素的优先级进行排序。默认情况下,它会按照元素的自然顺序(如数字从小到大、字符串按字典序)排列,也可通过传入 Comparator 自定义排序规则。PriorityQueue 基于二叉堆数据结构实现,每次出队(poll())操作会返回优先级最高的元素,插入操作的时间复杂度为 O (log n),出队操作的时间复杂度为 O (log n)。它适用于需要动态获取“最值”元素的场景,如任务调度中优先执行高优先级任务。

以下是创建 Queue 实例的示例:

// 创建 LinkedList 对象
Queue queueA = new LinkedList();
// 创建 PriorityQueue 对象
Queue queueB = new PriorityQueue();

注意,在大多数队列实现中,队列的头部和尾部位于相对的两端。然而,也可以实现队列接口,使得队列的头部和尾部位于同一端。在这种情况下,你得到的就是一个栈。

  

Queue 泛型

默认情况下,你可以将任何对象放入队列中,但从 Java 5 开始,Java 泛型使得限制可以插入队列的对象类型成为可能。例如:

Queue<String> queue = new LinkedList<String>();

现在这个队列只能插入 String 的实例。之后,你可以访问并迭代其元素,而无需对它们进行强制类型转换。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

for(String item : queue) {
    System.out.println(item);
}

注意,增强型 for 循环如何将队列中的每个元素直接转换为 String 实例,因为该队列是以 String 作为泛型类型创建的。

  

Queue 添加元素

Queue 接口提供了两个用于向队列添加元素的方法:add() 和 offer()。两者的核心功能一致,均是将元素插入队列的尾部(队尾)。

它们的关键区别体现在队列已满(无法容纳新元素)的场景中:

  • add() 方法会直接抛出 IllegalStateException 异常,明确标示队列已满的错误状态;

  • offer() 方法则会返回 false,不会抛出异常。

这种设计使得开发者可以根据实际场景选择更合适的处理方式 —— 需要严格校验容量时用 add(),希望避免异常处理时用 offer()。例如:

Queue<String> queue = new LinkedList<>();
queue.add("element 1");
queue.offer("element 2");

注意,LinkedList 本身是 Java 中一个无固定容量限制的集合(基于链表实现),默认情况下会随着元素的添加自动扩容,理论上仅受限于内存大小。因此调用 add() 和 offer() 不会存在队列已满的情况。可直接使用 java.util.concurrent.LinkedBlockingQueue,它本质上是基于链表的有界阻塞队列,构造时可指定容量:

LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(10);
for(int i = 0; i < 12; i++) {
    queue.add("item" + i);
}

运行上面代码将输出如下错误信息:

Exception in thread "main" java.lang.IllegalStateException: Queue full
	at java.base/java.util.AbstractQueue.add(AbstractQueue.java:98)

  

Queue 取出元素

从 Queue 中取出元素时,可使用 poll() 和 remove() 两种方法 —— 两者均会移除并返回队列的第一个元素(队首元素),区别如下:

  • 若队列为空,poll() 方法会返回 null。

  • 若队列为空,remove() 方法则会抛出 NoSuchElementException 异常。

这种设计允许开发者根据场景选择,需避免异常时用 poll(),需严格校验队列非空状态时用 remove()。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

String element1 = queue.poll();
System.out.println("element1=" + element1); //element1=one

String element2 = queue.remove();
System.out.println("element2=" + element2); //element2=two

上述代码,调用 poll() 方法将移除队列的第一个元素 —— 即第一个添加的字符串“one”。调用 remove() 方法将移除队列的第二个元素,在第一次调用 poll() 之后,这个元素现在是添加的 String 字符串“two”。

如果 Queue 为空,执行 poll() 和 remove() 方法效果如下:

Queue<String> queue = new LinkedList<>();

String element1 = queue.poll();
System.out.println("element1=" + element1); // element1=null

try {
    String element2 = queue.remove();
} catch (NoSuchElementException e) {
    System.out.println("出现异常了, " + e.getMessage()); // 出现异常了, null
}

  

Queue 查看

若想查看队列头部的元素而不将其从队列中移除,可使用 Queue 的 element() 或 peek() 方法。

其中,element() 方法会返回队列的第一个元素(队首元素);若队列为空,该方法会直接抛出 NoSuchElementException 异常。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

String firstElement = queue.element();
System.out.println(firstElement); //one

上述代码,firstElement 变量的值为“one”,这是队列(Queue)中的第一个元素。

peek() 方法的作用与 element() 方法类似,不同之处在于如果队列为空,它不会抛出异常,而是返回null。例如:

Queue<String> queue = new LinkedList<>();

queue.add("element 1");
queue.add("element 2");
queue.add("element 3");

String firstElement = queue.peek(); //one

  

Queue 移除元素

要从 Queue 中移除元素,需调用 remove() 方法,该方法会移除队列头部的元素。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

String removedElement = queue.remove();
System.out.println(removedElement); //one

还可以使用 Queue 的 clear() 方法移除所有元素。实际上,clear() 方法是从 Collection 接口继承而来的。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

queue.clear();
System.out.println(queue); //[]

  

Queue 队列大小

可以通过 Queue 的 size() 方法读取其存储的元素数量。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

System.out.println(queue.size()); //3

运行上述此代码,将输出 3,表示队列包含 3 个元素。

  

Queue 检查否包含元素

如果需要检查 Queue 中是否包含某个特定元素,可调用其 contains() 方法。如果 Queue 中存在与目标元素匹配的对象(匹配规则遵循 equals() 方法),则返回 true;若不存在,则返回 false。

注意,contains() 方法并非 Queue 接口原生定义,而是从其父接口 Collection 继承而来的基础方法,但这一实现细节对日常使用几乎无影响,开发者只需关注其 “检查元素是否存在” 的核心功能即可。例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

System.out.println("包含“one”元素?" + queue.contains("one")); //包含“one”元素?true
System.out.println("包含“five”元素?" + queue.contains("five")); //包含“five”元素?false

  

Queue 遍历所有元素

你也可以遍历 Queue 的所有元素,有三种方式进行遍历,分别如下:

(1)使用迭代器 Iterator,例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

Iterator<String> iterator = queue.iterator();
while(iterator.hasNext()) {
    System.out.println(iterator.next());
}

(2)使用增强 for 循环,例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

for(String item : queue) {
    System.out.println(item);
}

(3)使用 Stream API,例如:

Queue<String> queue = new LinkedList<>();
queue.add("one");
queue.add("two");
queue.add("three");

queue.stream().forEach(e -> {
    System.out.println(e);
});

查看更多信息见 https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html API 文档。

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号