Stack 在 Java 中已被标记为过时,因其继承 Vector 导致同步开销大、违背组合优于继承原则,且 JDK 推荐使用性能更优、语义更清晰的 ArrayDeque 替代。

为什么 Stack 在 Java 中已被标记为过时
Stack 继承自 Vector,所有操作(如 push()、pop())都带同步开销,即使你不需要线程安全。它的设计也违背了“组合优于继承”原则——Stack 并不是一种真正的“向量”,却强行复用其全部接口(比如能用 insertElementAt() 破坏栈结构)。JDK 文档明确建议使用 ArrayDeque 替代。
ArrayDeque 作为栈使用的正确写法
别调用 addFirst() / removeFirst()——虽然语义对得上,但可读性差且容易和队列逻辑混淆。应统一使用栈语义明确的双端方法:
-
push(E)等价于addFirst(e),推荐用于入栈 -
pop()等价于removeFirst(),推荐用于出栈(注意:空时抛NoSuchElementException) -
peek()等价于getFirst(),查看栈顶不移除
示例:
ArrayDeque<String> stack = new ArrayDeque<>();
stack.push("a");
stack.push("b");
String top = stack.pop(); // "b"
ArrayDeque 比 Stack 快在哪?关键差异点
性能优势来自三方面:
立即学习“Java免费学习笔记(深入)”;
-
ArrayDeque是非同步的,无锁开销;Stack每次push都走synchronized方法 -
ArrayDeque底层用循环数组,push/pop均为 O(1) 均摊时间;Stack虽也是数组,但因继承Vector,扩容策略更保守,且方法调用链更长 -
ArrayDeque不支持null元素,避免了运行时NullPointerException的模糊场景;Stack允许null,但peek()返回null时无法区分“栈空”还是“存了 null”
迁移时最容易踩的坑
直接把 Stack<t></t> 换成 ArrayDeque<t></t> 并不总能一劳永逸:
- 旧代码若用了
Stack特有方法(如search(Object)),ArrayDeque没有等价物,需手动遍历或改用ArrayList+ 索引计算 -
ArrayDeque的iterator()从栈底开始(即按插入顺序),而Stack.toString()显示的是“栈顶在右”的顺序——若依赖字符串表示做日志或调试,行为会变 - 多线程环境下,若原先靠
Stack的同步“凑合”用,换成ArrayDeque后必须显式加锁(如用Collections.synchronizedDeque())或换用ConcurrentLinkedDeque
真正需要栈语义时,ArrayDeque 几乎总是更好选择,但它的“干净”也意味着不会帮你掩盖设计问题——比如该用状态机的地方硬套栈,迁过去后问题只会更明显。



















