JAVA中栈的使用

栈(Stack)是遵循后进先出(LIFO, Last In First Out) 规则的线性数据结构,Java中有两种主流的栈实现方式:

  1. 遗留类:java.util.Stack(继承自Vector,线程安全但效率低,不推荐使用);
  2. 推荐方式:java.util.Deque(双端队列)接口的实现类(如LinkedListArrayDeque),功能更完善、效率更高,是官方推荐的栈替代方案。

一、栈的核心操作(按常用程度排序)

以下先统一说明核心操作的含义,再分别给出StackDeque的实现代码,重点讲解推荐的Deque用法。

操作名称 功能描述 Stack方法 Deque推荐方法(栈模式) 栈空时行为
入栈 将元素压入栈顶 push(E e) push(E e) / offerFirst(E e) 无异常(容量足够时)
出栈 移除并返回栈顶元素 pop() pop() / pollFirst() pop抛异常;pollFirst返回null
查看栈顶 返回栈顶元素但不移除 peek() peek() / peekFirst() peek抛异常;peekFirst返回null
判空 判断栈是否为空 isEmpty() isEmpty() -
获取大小 返回栈中元素个数 size() size() -
清空栈 移除栈中所有元素 clear() clear() -
检查元素 判断栈中是否包含指定元素 contains(Object o) contains(Object o) -

二、代码示例(推荐Deque实现)

1. 基础操作示例(Deque + ArrayDeque)

ArrayDeque是Deque的数组实现,效率高于LinkedList,是栈的首选实现:

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

public class StackOperationsDemo {
    public static void main(String[] args) {
        // 1. 初始化栈(Deque作为栈使用,推荐ArrayDeque)
        Deque<Integer> stack = new ArrayDeque<>();

        // 2. 入栈(push)
        stack.push(1); // 栈:[1]
        stack.push(2); // 栈:[2, 1]
        stack.push(3); // 栈:[3, 2, 1]
        System.out.println("入栈后栈内容:" + stack); // 输出 [3, 2, 1](Deque打印顺序是头到尾,栈顶是头)

        // 3. 查看栈顶(peek)
        Integer topElement = stack.peek();
        System.out.println("栈顶元素:" + topElement); // 输出 3(栈顶不变)
        System.out.println("查看栈顶后栈内容:" + stack); // 输出 [3, 2, 1]

        // 4. 出栈(pop)
        Integer popElement = stack.pop();
        System.out.println("出栈元素:" + popElement); // 输出 3
        System.out.println("出栈后栈内容:" + stack); // 输出 [2, 1]

        // 5. 判空(isEmpty)
        boolean isEmpty = stack.isEmpty();
        System.out.println("栈是否为空:" + isEmpty); // 输出 false

        // 6. 获取栈大小(size)
        int size = stack.size();
        System.out.println("栈大小:" + size); // 输出 2

        // 7. 检查元素是否存在(contains)
        boolean contains = stack.contains(1);
        System.out.println("栈是否包含1:" + contains); // 输出 true

        // 8. 清空栈(clear)
        stack.clear();
        System.out.println("清空后栈是否为空:" + stack.isEmpty()); // 输出 true

        // 9. 安全出栈/查看(避免空栈异常)
        // pollFirst:栈空返回null,不抛异常(替代pop)
        Integer safePop = stack.pollFirst();
        System.out.println("空栈安全出栈:" + safePop); // 输出 null
        // peekFirst:栈空返回null,不抛异常(替代peek)
        Integer safePeek = stack.peekFirst();
        System.out.println("空栈安全查看栈顶:" + safePeek); // 输出 null
    }
}

2. 遗留类Stack的示例(了解即可,不推荐)

java.util.Stack是遗留类,继承自Vector,线程安全但性能差,且方法命名和Deque一致,示例如下:

java 复制代码
import java.util.Stack;

public class LegacyStackDemo {
    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();

        // 入栈
        stack.push("A");
        stack.push("B");

        // 查看栈顶
        System.out.println("栈顶:" + stack.peek()); // B

        // 出栈
        System.out.println("出栈:" + stack.pop()); // B

        // 判空
        System.out.println("是否为空:" + stack.isEmpty()); // false

        // 栈空时pop/peek会抛EmptyStackException
        stack.pop(); // 栈变为空
        // stack.pop(); // 抛EmptyStackException
    }
}

三、关键注意事项

  1. 空栈异常Stack.pop()/Stack.peek()Deque.pop()/Deque.peek()在栈空时会抛出EmptyStackException/NoSuchElementException,推荐使用Deque.pollFirst()/Deque.peekFirst()(返回null,更安全);
  2. 线程安全Stack是线程安全的(基于Vector的同步方法),但效率低;ArrayDeque/LinkedList非线程安全,若需线程安全的栈,可使用Collections.synchronizedDeque(new ArrayDeque<>())
  3. Deque作为栈的规范 :Deque是双端队列,作为栈使用时,仅使用push()/pop()/peek()(等价于offerFirst()/removeFirst()/peekFirst()),避免使用队列相关方法(如add()/remove()),保证栈的LIFO规则。

总结

  1. Java栈核心操作包括入栈(push)出栈(pop)查看栈顶(peek)判空(isEmpty)获取大小(size)清空(clear) 等;
  2. 不推荐使用遗留类java.util.Stack,优先选择Deque接口(ArrayDeque/LinkedList)实现栈功能;
  3. 空栈操作时,优先使用pollFirst()/peekFirst()替代pop()/peek(),避免空指针异常,提升代码健壮性。
相关推荐
sanshizhang1 小时前
jspringboot 调用腾讯短信
java·短信验证码
Tong Z1 小时前
Spring Boot 请求处理链路
java·spring boot·后端
rabbitlzx1 小时前
《Async in C# 5.0》第十四章 深入探讨编译器对于async的转换
java·开发语言·c#·异步·asynchronous
LSL666_1 小时前
3 Redis 的 Java 客户端
java·数据库·redis
虫师c1 小时前
Spring Boot自动配置黑魔法:手写Starter实现原理深度解析
java·spring boot·后端·自动配置·starter
神明不懂浪漫2 小时前
【第十三章】操作符详解,预处理指令详解
c语言·开发语言·经验分享·笔记
MediaTea2 小时前
Python:类型槽位
开发语言·python
范什么特西2 小时前
狂神---死锁
java·前端·javascript
郝学胜-神的一滴2 小时前
深入解析Effective Modern C++条款35:基于任务与基于线程编程的哲学与实践
开发语言·数据结构·c++·程序人生