应停用stack类,改用arraydeque:stack自java 6起被标记为@deprecated,存在同步开销、违背lifo语义等问题;arraydeque无同步、性能高3–5倍、语义清晰,是官方推荐替代方案。

Java里还在用Stack类?赶紧停手
Java的Stack类从JDK 1.0就存在,但它继承自Vector,所有操作都带同步开销,且设计上违背了LIFO语义(比如能用elementAt()随机访问)。它早在Java 6就被官方标记为@Deprecated,不是“不推荐”,是“明确不鼓励使用”。真实项目里还见到new Stack(),基本等于在代码里埋了个性能+可维护性双雷。
用ArrayDeque替代Stack:为什么是首选
ArrayDeque是JDK 6引入的、专为双端队列优化的实现,它内部用循环数组,无同步、扩容策略合理、内存局部性好。作为栈用时,push()/pop()/peek()语义清晰,性能比Stack高3–5倍(尤其在频繁压栈/出栈场景)。它实现了Deque接口,但你不需关心“双端”——只用栈那一侧就行。
-
push(e)等价于addFirst(e),不是addLast() -
pop()会抛NoSuchElementException(不是EmptyStackException),这点和Stack行为不同 - 不能存
null——ArrayDeque明确禁止null元素,而Stack允许 - 初始化时别写
new ArrayDeque(0),最小容量是16;想控制初始大小,传入≥16的值才有效
LinkedList也能当栈?别被误导
虽然LinkedList也实现了Deque,能调push()/pop(),但它底层是链表,每次操作都要分配/回收节点对象,GC压力大,缓存不友好。在中等以上数据量(比如千级元素)下,ArrayDeque的吞吐量通常是LinkedList的2倍以上。只有极特殊场景(比如栈深度极大但内存受限,且必须避免数组扩容抖动),才考虑LinkedList——但这种场景99%不存在。
- 不要因为“它看起来更‘通用’”就选
LinkedList -
LinkedList的push()其实是addFirst(),但它的size()是O(n),而ArrayDeque是O(1) - 如果代码里已经用了
LinkedList做栈,改起来很简单:new LinkedList()→new ArrayDeque(),方法名完全兼容
迁移Stack时最常踩的三个坑
直接替换类名不行,得改调用逻辑。老代码里常见这些写法,不处理就会出错:
立即学习“Java免费学习笔记(深入)”;
- 用
stack.elementAt(0)或stack.get(0)取栈顶?ArrayDeque没这方法——改用peek(),或者先isEmpty()判断再peek() - 捕获
EmptyStackException?ArrayDeque.pop()抛的是NoSuchElementException——要么统一用isEmpty()预检,要么catch新异常类型 - 把
Stack当集合遍历:for (Object o : stack)在ArrayDeque里是按从栈底到栈顶顺序,和Stack的Enumeration顺序相反——如果业务依赖这个顺序,得显式用descendingIterator()
栈结构本身简单,但历史包袱让替换不完全是“换个构造器”的事。真正麻烦的从来不是语法,而是那些藏在if分支里、日志里、单元测试断言里的隐式假设。










