📚 Java 23 集合框架详解:Deque
接口及实现类(ArrayDeque
、LinkedList
)
📖 1. 概述
Deque
(Double-Ended Queue) 接口是 Java 集合框架中用于实现 双端队列 的接口,它支持在 队列头部和尾部插入和删除元素。与 Queue
接口不同,Deque
支持 双向操作,可以充当 栈(LIFO) 和 队列(FIFO)。
🔑 主要实现类
ArrayDeque
:基于 数组 的双端队列实现,性能高,适用于大多数场景。LinkedList
:基于 双向链表 的双端队列实现,插入和删除性能好,适用于频繁操作头尾元素的场景。
📋 2. Deque 接口常用方法
方法 | 描述 |
---|---|
addFirst(E e) | 将元素插入到队列头部 |
addLast(E e) | 将元素插入到队列尾部 |
offerFirst(E e) | 将元素插入到队列头部(不抛异常) |
offerLast(E e) | 将元素插入到队列尾部(不抛异常) |
removeFirst() | 移除并返回队列头部的元素 |
removeLast() | 移除并返回队列尾部的元素 |
pollFirst() | 获取并移除队列头部的元素(为空返回 null ) |
pollLast() | 获取并移除队列尾部的元素(为空返回 null ) |
getFirst() | 获取但不移除队列头部的元素 |
getLast() | 获取但不移除队列尾部的元素 |
📋 3. ArrayDeque
详解
✅ 3.1 特点
- 基于数组实现,可动态扩容。
- 不允许存储
null
值。 - 性能优于
LinkedList
,特别是在作为 栈 或 队列 使用时。 - 提供了比
Stack
更好的替代方案。
🔧 3.2 使用案例
✅ 作为队列使用(FIFO)
import java.util.ArrayDeque;
public class ArrayDequeQueueExample {
public static void main(String[] args) {
ArrayDeque<String> queue = new ArrayDeque<>();
// 添加元素到队列尾部
queue.offer("Alice");
queue.offer("Bob");
queue.offer("Charlie");
// 遍历队列
System.out.println("Queue Elements:");
queue.forEach(System.out::println);
// 获取并移除队列头部元素
System.out.println("Polled Element: " + queue.poll());
// 查看队列头部元素
System.out.println("Peek Element: " + queue.peek());
}
}
输出:
Queue Elements:
Alice
Bob
Charlie
Polled Element: Alice
Peek Element: Bob
✅ 作为栈使用(LIFO)
import java.util.ArrayDeque;
public class ArrayDequeStackExample {
public static void main(String[] args) {
ArrayDeque<String> stack = new ArrayDeque<>();
// 添加元素到栈顶
stack.push("Alice");
stack.push("Bob");
stack.push("Charlie");
// 遍历栈
System.out.println("Stack Elements:");
stack.forEach(System.out::println);
// 获取并移除栈顶元素
System.out.println("Popped Element: " + stack.pop());
// 查看栈顶元素
System.out.println("Peek Element: " + stack.peek());
}
}
输出:
Stack Elements:
Charlie
Bob
Alice
Popped Element: Charlie
Peek Element: Bob
🛠 3.3 优化方案
- 避免存储
null
值,因为ArrayDeque
不支持null
。 - 优先使用
ArrayDeque
代替Stack
,因为Stack
是一个老旧的类,性能较低且不推荐使用。
⚠️ 3.4 多线程优化
ArrayDeque
是 线程不安全的,如果在多线程环境中使用,可以使用 ConcurrentLinkedDeque
。
📋 4. LinkedList
详解
✅ 4.1 特点
- 基于双向链表实现,支持高效的插入和删除操作。
- 允许存储
null
值。 - 既可以用作 列表,也可以用作 双端队列。
🔧 4.2 使用案例
✅ 作为队列使用(FIFO)
import java.util.LinkedList;
import java.util.Deque;
public class LinkedListQueueExample {
public static void main(String[] args) {
Deque<String> queue = new LinkedList<>();
// 添加元素到队列尾部
queue.offer("Alice");
queue.offer("Bob");
queue.offer("Charlie");
// 遍历队列
System.out.println("Queue Elements:");
queue.forEach(System.out::println);
// 获取并移除队列头部元素
System.out.println("Polled Element: " + queue.poll());
// 查看队列头部元素
System.out.println("Peek Element: " + queue.peek());
}
}
✅ 作为栈使用(LIFO)
import java.util.LinkedList;
public class LinkedListStackExample {
public static void main(String[] args) {
LinkedList<String> stack = new LinkedList<>();
// 添加元素到栈顶
stack.push("Alice");
stack.push("Bob");
stack.push("Charlie");
// 遍历栈
System.out.println("Stack Elements:");
stack.forEach(System.out::println);
// 获取并移除栈顶元素
System.out.println("Popped Element: " + stack.pop());
// 查看栈顶元素
System.out.println("Peek Element: " + stack.peek());
}
}
🛠 4.3 优化方案
- 避免频繁随机访问,因为
LinkedList
的随机访问性能较差。 - 优先使用
ArrayDeque
,如果不需要存储大量元素且对内存占用敏感。
⚠️ 4.4 多线程优化
LinkedList
是 线程不安全的,在多线程环境中可以使用 ConcurrentLinkedDeque
。
🔄 5. 两者对比总结
特性 | ArrayDeque | LinkedList |
---|---|---|
底层数据结构 | 动态数组 | 双向链表 |
是否允许 null 值 | 否 | 是 |
插入/删除性能 | 高 | 高 |
随机访问性能 | 高 | 低 |
适用场景 | 栈、队列操作 | 队列、列表操作 |
🎯 6. 选择指南
场景 | 推荐实现类 |
---|---|
栈操作(LIFO) | ArrayDeque |
队列操作(FIFO) | ArrayDeque |
需要存储 null 值 | LinkedList |
频繁插入和删除操作 | LinkedList |
多线程环境 | ConcurrentLinkedDeque |
⚙️ 7. 总结
ArrayDeque
是最推荐的双端队列实现,性能优于LinkedList
,适用于大多数场景。LinkedList
适用于需要存储null
值或频繁插入和删除操作的场景。- 在多线程环境中,建议使用
ConcurrentLinkedDeque
代替。