In real-world Java development, data structures often need to support both stack (LIFO) and queue (FIFO) operations efficiently. This is where Deque (Double-Ended Queue) shines — a hybrid structure that allows insertions and deletions from both ends. ArrayDeque is its most widely used implementation, offering blazing-fast performance for both ends.
Whether you're building compilers, caching systems, or algorithmic solutions (like sliding window problems), mastering Deque and ArrayDeque is essential.
What Is Deque in Java?
Definition
A Deque (pronounced "deck") is a linear collection that supports insertion and removal of elements at both ends: front and rear.
Deque<String> deque = new ArrayDeque<>();
Key Features
- Supports stack and queue operations.
- Null elements are not allowed in
ArrayDeque. - Efficient O(1) performance for add/remove operations at both ends.
ArrayDeque – Java’s Fastest Deque Implementation
Internal Working
- Backed by a resizable circular array.
- Automatically doubles in size when capacity is exceeded.
- Uses two pointers: head and tail.
- No thread-safety; prefer
ConcurrentLinkedDequefor concurrency.
Memory Layout
+-----------------------------------------+
| null | A | B | C | null | null | null |
+-----------------------------------------+
↑ ↑
head tail
When resized, it wraps around to use all available space.
Java Syntax and Methods
Creating a Deque
Deque<Integer> deque = new ArrayDeque<>();
Common Operations
| Operation | Method | Description |
|---|---|---|
| Add to front | addFirst(e) |
Adds element to front |
| Add to rear | addLast(e) |
Adds element to rear |
| Remove from front | removeFirst() |
Removes and returns front element |
| Remove from rear | removeLast() |
Removes and returns rear element |
| Peek front | peekFirst() |
Views front element |
| Peek rear | peekLast() |
Views rear element |
| Stack push | push(e) |
Adds element to front (like a stack) |
| Stack pop | pop() |
Removes and returns front (like a stack) |
Code Example – Deque as Stack and Queue
Deque<String> deque = new ArrayDeque<>();
// Queue behavior (FIFO)
deque.addLast("A");
deque.addLast("B");
System.out.println(deque.removeFirst()); // A
// Stack behavior (LIFO)
deque.push("C");
deque.push("D");
System.out.println(deque.pop()); // D
Performance and Big-O
| Operation | Time Complexity |
|---|---|
| Add/Remove (head/tail) | O(1) |
| Resize (amortized) | O(n) |
| Search | O(n) |
Real-World Use Cases
- Sliding window algorithms
- Backtracking problems
- Undo/redo stacks
- Task schedulers
- Browser history navigation
Comparisons
ArrayDeque vs LinkedList
| Feature | ArrayDeque | LinkedList |
|---|---|---|
| Backing | Resizable array | Doubly linked list |
| Null allowed? | ❌ No | ✅ Yes |
| Memory usage | Lower | Higher |
| Random access | ❌ No | ❌ No |
| Thread-safe | ❌ No | ❌ No |
Functional Programming Support
Deque<String> deque = new ArrayDeque<>(List.of("X", "Y", "Z"));
deque.stream()
.filter(s -> s.contains("Y"))
.forEach(System.out::println);
📌 What's New in Java Versions?
- Java 8
- Stream API compatible with
Deque - Lambda-based filtering and iteration
- Stream API compatible with
- Java 9
List.of(),Set.of()for factory methods (useful in initializing)
- Java 10+
varfor type inference:var dq = new ArrayDeque<String>();
- Java 21
- Improved memory optimizations for small collections
Anti-Patterns and Misuse Cases
- Using
ArrayDequewhere thread-safety is required → preferConcurrentLinkedDeque - Adding
null→ throwsNullPointerException - Treating Deque as purely FIFO or LIFO → underutilizes its capabilities
Refactoring Legacy Code
Before:
Stack<Integer> stack = new Stack<>();
After:
Deque<Integer> stack = new ArrayDeque<>();
✅ ArrayDeque is preferred over Stack (which is synchronized and legacy).
Best Practices
- Always prefer
ArrayDequeoverStack - Avoid using
null - Use
Dequewhen you need both FIFO and LIFO operations - Use LinkedList only when frequent element removals in the middle are required
Conclusion & Key Takeaways
Dequeis a versatile data structure combining features of both stack and queue.ArrayDequeoffers fast, memory-efficient implementation.- Avoid
StackandLinkedListunless necessary. - Leveraging
Dequein modern Java improves clarity and performance.
FAQ – Advanced Concepts
1. Why use ArrayDeque over Stack?
Because Stack is synchronized and legacy. ArrayDeque is faster and recommended.
2. Is ArrayDeque thread-safe?
No. Use ConcurrentLinkedDeque for concurrent scenarios.
3. Can we add null to ArrayDeque?
No. Nulls are not allowed and throw NullPointerException.
4. What happens if capacity is exceeded?
Internally resizes (doubles in size).
5. What’s the initial capacity of an ArrayDeque?
Default is 16 (and grows as needed).
6. When is LinkedList better than ArrayDeque?
Only when you need frequent insertions/removals from middle of the list.
7. What is the backing data structure?
A resizable circular array.
8. What is Deque short for?
Double-Ended Queue.
9. Can I use Deque with Streams?
Yes, you can use any Collection with Stream API.
10. Is there a Deque for priority-based access?
No. Use PriorityQueue or TreeSet for sorted access.