Java ArrayDeque 怎样实现双端队列的首尾操作
来源:17golang原创
时间:2026-10-20 00:45:27 312浏览 收藏
我第一次把双端队列接进任务调度代码时,真正容易写错的不是 new ArrayDeque(),而是“这一端到底是谁”和“空了以后要异常还是要特殊值”。先给结论:ArrayDeque 用 first 表示头部、last 表示尾部;需要明确失败就用 add/remove/element 这一组,需要把空队列当成普通分支就用 offer/poll/peek。它不允许存入 null,也不是线程安全容器。
官方地址:https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/ArrayDeque.html
下面的示例只讨论首尾操作和边界,不把 ArrayDeque 包装成共享并发队列,也不把静态说明图当成运行截图。
先把 first 和 last 分清楚
ArrayDeque 是 Deque 的可扩容数组实现。对一个普通队列,可以把头部理解为下一次取出的方向,把尾部理解为新元素通常追加的方向;对双端队列,两边都能插入、删除和查看。我的经验是先在变量旁写清“头部/尾部”,再选方法名,避免只凭 add 和 remove 猜方向。

需要从头部放入元素时,用 addFirst(e);从尾部放入时,用 addLast(e)。删除对应使用 removeFirst() 和 removeLast(),只查看而不删除则使用 peekFirst() 和 peekLast()。这些名字比把队列当作一条没有方向的容器更适合维护。
插入、删除、查看:先决定失败语义
Queue 和 Deque 的一组方法有意分成两种风格:一组失败时抛异常,另一组返回特殊值。ArrayDeque 没有固定容量限制,所以插入通常不会因为“满了”而失败,但方法成对语义仍然值得保留。
| 目的 | 明确失败 | 普通分支 |
|---|---|---|
| 插入头部 | addFirst | offerFirst |
| 删除头部 | removeFirst | pollFirst |
| 查看头部 | getFirst | peekFirst |
| 队列尾部 | add | offer |
| 删除队头 | remove | poll |
| 查看队头 | element | peek |
例如,空队列可能是业务允许的“没有待处理任务”,就可以用 poll() 或 peek() 让调用方判断 null。如果空队列说明程序状态已经不对,remove() 或 element() 抛出的 NoSuchElementException 会更早暴露问题。

用代码把首尾选择写出来
下面把两个常见意图放在一起:任务队列从尾部加入、从头部取出;撤销栈则只使用头部。注释只解释关键语义,避免把每一行都写成注释。
import java.util.ArrayDeque;
public class ArrayDequeEnds {
public static void main(String[] args) {
var tasks = new ArrayDeque();
// 尾部追加新任务,头部取出最早进入的任务
tasks.addLast("编译");
tasks.addLast("打包");
String next = tasks.pollFirst();
System.out.println(next); // 预期示例输出:编译
var undo = new ArrayDeque();
// push 等价于 addFirst,适合把同一端当作栈顶
undo.push("改配置");
undo.push("改代码");
String latest = undo.pop();
System.out.println(latest); // 预期示例输出:改代码
// peek 只查看,不删除;空队列时返回 null
String waiting = tasks.peekFirst();
if (waiting == null) {
System.out.println("没有待处理任务");
}
}
}
push(e) 是把元素放到头部的栈式表达,pop() 则从头部删除并返回。若读者看到的是“撤销最近一次操作”,push/pop 比 addFirst/removeFirst 更能表达意图;若读者看到的是“双端数据结构”,首尾方法名更直接。
空队列、null 和共享访问要单独处理
ArrayDeque 禁止 null 元素,这反而让 poll、peek 返回 null 时具有明确含义:队列为空,而不是取出了一个合法的 null。不要为了绕过判断把 null 当作占位元素塞进去。
另外,ArrayDeque 没有内部同步。单线程任务循环、局部的请求处理和明确由一个所有者管理的工作队列都可以考虑它;多个线程同时修改同一个实例时,不能仅因为类型名里有 Queue 就认为它提供并发安全。需要跨线程传递任务时,应另行选择并发队列或在外部建立同步边界。
我会在代码评审里检查三件事:调用方是否已经决定空队列是异常还是分支;方法名是否和数据方向一致;容器是否被多个线程共享。三项都清楚,ArrayDeque 的 API 基本不会再靠记忆猜。
相关问题
- ArrayDeque 的 add 和 offer 怎么选? 两者都表示插入;当失败应作为异常暴露时用 add,需要用返回值表达插入失败时用 offer。
- poll 和 remove 的区别是什么? 两者都会删除并返回队头;空队列时 poll 返回 null,remove 抛出 NoSuchElementException。
- ArrayDeque 能不能存 null? 不能。空队列返回 null 的约定也依赖这个限制。
- push 和 addFirst 有什么关系? push 是栈语义的头部插入别名;选择它还是 addFirst,取决于你想表达栈还是双端队列。
-
501 收藏
-
文章 · java教程 | 1个月前 | Java · 异常处理 · 资源管理 · java try-with-resources AutoCloseable close suppressed exception501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
241 收藏
-
345 收藏
-
279 收藏
-
494 收藏
-
320 收藏
-
文章 · java教程 | 48分钟前 | Java · 集合 · 资源管理 · Stream · Java教程 · supplier Java Stream Files.lines Stream生命周期 重复遍历146 收藏
-
165 收藏
-
218 收藏
-
366 收藏
-
126 收藏
-
339 收藏
-
205 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习