1. Introduction
The ArrayDeque class in Java is a resizable-array implementation of the Deque
interface. It supports both stack (LIFO) and queue (FIFO) operations, offering an efficient and modern alternative to the legacy Stack
class, and a more memory-efficient option than LinkedList.
“Why choose between a stack and a queue when you can have both?”
This article explores the internal structure of ArrayDeque, its performance traits, and common real-world use cases. To see how it compares to other queues, refer to our Java Queue Implementations article.
2. Internal Structure
Internally, ArrayDeque uses a circular array to store elements. This design enables constant-time insertions and deletions at both ends. When the array becomes full, it is resized to accommodate additional elements.
Key Characteristics:
- Resizable: Automatically grows as needed.
- Nulls not allowed: Inserting
null
throws NullPointerException. - Not thread-safe: External synchronization is required for concurrent access.
This structure avoids the overhead of linked nodes and provides better cache locality and memory usage than a LinkedList.
3. Performance Characteristics
ArrayDeque is designed for high performance. The average time complexities for core operations are:
- Add/Remove First: O(1)
- Add/Remove Last: O(1)
- Peek First/Last: O(1)
Unlike Stack
, which synchronizes methods unnecessarily, ArrayDeque
offers non-blocking, single-threaded performance.
“ArrayDeque combines speed and flexibility in one robust structure.”
4. Use Cases of ArrayDeque
Due to its versatility and performance, ArrayDeque
fits well in many scenarios:
- Implementing stacks with
push()
andpop()
. - Building queues with
offer()
andpoll()
. - Undo/Redo functionality in editors.
- Tree traversal (BFS using queue, DFS using stack).
- Buffering mechanisms in parsers or data streams.
When you need a double-ended queue without thread-safety concerns, ArrayDeque
should be your go-to choice.
5. Practical Code Demonstration
The following examples illustrate the versatility of ArrayDeque in both stack and queue modes.
5.1 Using ArrayDeque as a Stack
We can use push()
to add elements to the front and pop()
to remove them in LIFO order.
Deque<String> stack = new ArrayDeque<>();
stack.push("First");
stack.push("Second");
System.out.println(stack.pop()); // Second
5.2 Using ArrayDeque as a Queue
We use offer()
to insert at the end and poll()
to remove from the front, mimicking FIFO behavior.
Deque<String> queue = new ArrayDeque<>();
queue.offer("Task1");
queue.offer("Task2");
System.out.println(queue.poll()); // Task1
5.3 Accessing Both Ends
You can access or manipulate both ends efficiently with methods like peekFirst()
and peekLast()
.
queue.offerFirst("Urgent");
System.out.println(queue.peekLast()); // Task2
6. Limitations and Alternatives
Despite its advantages, ArrayDeque
has some limitations:
- ❌ Not thread-safe (consider
ConcurrentLinkedDeque
if needed). - ❌ Cannot contain
null
elements. - ❌ Fixed growth rate (doubling size when full).
Alternatives:
- Use
LinkedList
if null elements or bidirectional iteration are required. - Use
Stack
only for legacy code compatibility.
7. Conclusion
ArrayDeque is a highly efficient, flexible, and reliable structure for implementing stacks and queues in Java. With low memory overhead and fast operations at both ends, it outperforms older alternatives in almost every scenario.
“Choose ArrayDeque when performance meets versatility.”
You can find the complete code for this article on GitHub.