🔥 本文深入剖析Java集合框架中的ArrayDeque,从基础应用到实战案例,带你全面掌握这个重要的有序集合类。本文是ArrayDeque系列的下篇,主要关注实战应用与面试重点。
📚 系列专栏推荐:

🌟 特色亮点:
- 丰富的实战案例分析
- 深入的性能优化指南
- 常见踩坑问题总结
- 面试高频题详解
- 最佳实践经验分享
四、ArrayDeque实战应用
在实际开发中,ArrayDeque就像一把瑞士军刀,能够适应各种不同的场景。让我们通过实际案例,一步步掌握它的使用技巧。
1. 作为栈使用(替代Stack)
想象一下,你正在开发一个网页的后退功能,需要记录用户访问过的页面。这时候就需要一个栈结构,那么应该选择传统的Stack还是ArrayDeque呢?
1.1 为什么要替代Stack?
让我们先看看老朋友Stack的问题:
- 继承自Vector,带有同步开销(即使你不需要线程安全)
- API设计不合理,违反LIFO原则(例如search方法从1开始计数)
- 性能较差,内存占用大(Vector的遗留问题)
- 官方已经不推荐使用(Java文档中明确建议使用Deque)
1.2 替换方案
来看看如何优雅地替换Stack:
// 旧代码:使用Stack
Stack<String> stack = new Stack<>();
stack.push("第一个元素");
stack.pop();
stack.peek();
// 新代码:使用ArrayDeque
ArrayDeque<String> stack = new ArrayDeque<>();
stack.push("第一个元素"); // 压栈
stack.pop(); // 弹栈
stack.peek(); // 查看栈顶
是不是很简单?API几乎是一模一样的,但性能却提升了不少。
1.3 实战案例:表达式求值
让我们来解决一个经典问题:计算简单的数学表达式。比如"3+5-2"应该等于6。
这个问题看似简单,但如果不用栈结构,代码会变得非常复杂。
public class ExpressionCalculator {
public static int calculate(String expression) {
// 用两个栈分别存储数字和运算符
ArrayDeque<Integer> numbers = new ArrayDeque<>();
ArrayDeque<Character> operators = new ArrayDeque<>();
// 逐字符处理表达式
for (char c : expression.toCharArray()) {
if (Character.isDigit(c)) {
// 遇到数字直接入栈
numbers.push(c - '0');
} else if (c == '+' || c == '-') {
// 遇到运算符,先计算前面的结果
while (!operators.isEmpty()) {
compute(numbers, operators);
}
operators.push(c);
}
}
// 处理剩余的运算
while (!operators.isEmpty()) {
compute(numbers, operators);
}
return numbers.pop(); // 最终结果
}
private static void compute(ArrayDeque<Integer> numbers,
ArrayDeque<Character> operators) {
// 取出两个数字和一个运算符进行计算
int b = numbers.pop();
int a = numbers.pop();
char op = operators.pop();
numbers.push(op == '+' ? a + b : a - b);
}
}
// 使用示例
int result = ExpressionCalculator.calculate("3+5-2"); // 结果:6
这个实现的巧妙之处在于:
- 使用两个栈分别管理数字和运算符
- 遇到新运算符时,先处理之前的运算
- 保证了运算顺序的正确性
- 代码结构清晰,易于扩展
2. 作为队列使用(替代LinkedList)
假设你正在开发一个消息处理系统,需要按照先进先出(FIFO)的顺序处理消息。传统上我们可能会使用LinkedList,但ArrayDeque可能是更好的选择。
2.1 为什么选择ArrayDeque?
让我们比较一下两者的区别:
- 内存占用更少(没有节点对象的开销)
- 访问性能更好(数据在内存中连续存储)
- API更清晰(专注于队列操作)
- CPU缓存友好(连续内存访问)
2.2 队列操作示例
来看一个简单的消息队列实现:
// 创建消息队列
ArrayDeque<String> messageQueue = new ArrayDeque<>();
// 生产消息
messageQueue.offer("消息1"); // 入队
messageQueue.offer("消息2");
messageQueue.offer("消息3");
// 消费消息
while (!messageQueue.isEmpty()) {
String message = messageQueue.poll(); // 出队
processMessage(message);
}
// 查看但不删除
String peek = messageQueue.peek(); // 查看队首
注意这里使用的是offer/poll而不是add/remove,因为前者在操作失败时会返回false/null,而不是抛出异常。
2.3 实战案例:任务调度器
在实际开发中,我们经常需要处理任务队列。比如一个打印任务队列,或者一个下载任务队列。让我们来实现一个简单但实用的任务调度器:
public class TaskScheduler {
private ArrayDeque<Runnable> taskQueue = new ArrayDeque<>();
// 添加任务
public void addTask(Runnable task) {
taskQueue.offer(task);
}
// 执行任务
public void executeTasks(

最低0.47元/天 解锁文章
1132

被折叠的 条评论
为什么被折叠?



