Course contents

Queue, Deque and ArrayDeque

Queue, Deque and ArrayDeque: method families, FIFO and stack usage, circular-array internals, BFS, monotonic deques and when to choose BlockingQueue.

PremiumMust know for interviewsLesson12 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: a circular waiting line
  2. Queue under the hood: two method families
  3. Deque as both queue and stack
  4. ArrayDeque internals: head, tail and growth
  5. BFS: the queue pattern everyone should know
  6. Sliding window maximum: the monotonic deque
  7. Choosing between ArrayDeque, LinkedList and BlockingQueue
  8. How to say it in the interview

🚦 What are Queue, Deque and ArrayDeque?

A Queue is a collection where removal follows a policy, most often FIFO: first in, first out. A Deque is a double-ended queue, so you can add or remove at both the front and the back. ArrayDeque is the usual in-memory implementation, backed by a circular Object[], like a ticket counter with a front door, a back door and a belt that wraps around.

For this lesson, we'll focus on the Queue method families, Deque as both queue and stack, ArrayDeque internals, why it usually beats Stack and LinkedList, and the interview patterns you should write from memory: FIFO scheduling, BFS and a monotonic deque for sliding windows. We'll leave priority ordering to PriorityQueue and binary heaps and thread coordination to Blocking and concurrent queues at a glance.

Below the line (out of scope)

The 30-second answer

Queue has two families: add, remove, element throw when they cannot complete; offer, poll, peek return a special value such as false or null. Deque extends that idea to both ends: addFirst, removeFirst, peekFirst, and the same for the last end. Its stack methods map to the front: push is addFirst, pop is removeFirst, and peek is peekFirst. ArrayDeque stores elements in a circular Object[] with head pointing at the first element and tail at the next empty slot. It rejects null because poll uses null to mean empty, is not thread-safe, and has fail-fast iterators. For single-threaded queues and stacks, prefer ArrayDeque over legacy Stack and usually over LinkedList; if producers and consumers are separate threads and must wait, use a BlockingQueue.

What you’ll learn

  • Separate the two Queue method families: throwing (add, remove, element) and special-value (offer, poll, peek)
  • Use Deque as both a FIFO queue and a LIFO stack, with push, pop and peek mapped to the front
  • Explain ArrayDeque internals: circular Object[], head, tail, no null, growth and fail-fast iterators
  • Choose ArrayDeque over legacy Stack and usually over LinkedList for single-threaded queues and stacks
  • Recognize when a FIFO producer-consumer prompt needs a BlockingQueue instead of ArrayDeque
  • Write BFS with a queue and sliding-window maximum with a monotonic deque

Interview radar

Asked very often: Which queue method returns null instead of throwing, and why is ArrayDeque preferred over Stack? Core follow-up: How does a circular array avoid shifting elements on every poll? Production angle: A job scheduler prompt says FIFO, but if it also says producers wait when the queue is full, the answer changes from ArrayDeque to BlockingQueue.

01Picture it first: a circular waiting line

Think of an ArrayDeque as seats arranged in a circle, not a straight line. head marks the next person to serve. tail marks the next empty seat where a new person joins. When either marker reaches the end of the array, it wraps back to slot 0.

The trick is no shifting. Removing the front element clears one slot and moves head; adding at the back writes one slot and moves tail.

Fig. 1

ArrayDeque circular buffer with an Object array, head pointing to the first element, tail pointing to the next empty slot, and wrapped live elements occupying the end and beginning of the array

ArrayDeque circular buffer with an Object array, head pointing to the first element, tail pointing to the next empty slot, and wrapped live elements occupying the end and beginning of the array

Notice the empty slot at tail. Internally, ArrayDeque keeps enough space to distinguish full from empty and grows when an add would make the markers collide. It does not store null elements, which lets poll, peek and empty slots all use null safely.

02Queue under the hood: two method families

The Queue interface gives every core operation two names. One family throws on failure. The other returns a special value. The right choice depends on whether failure is exceptional or expected.

Operation Throws on failure Returns special value
Insert add(e) offer(e) returns false
Remove head remove() poll() returns null
Inspect head element() peek() returns null

For unbounded ordinary queues, add and offer usually both succeed. The difference matters for bounded queues such as ArrayBlockingQueue, where offer can say false instead of throwing.

Try it yourself first

Before reading on, predict which three lines throw on an empty queue and which two print null.

Queue<String> jobs = new ArrayDeque<>();

System.out.println(jobs.peek());    // null
System.out.println(jobs.poll());    // null

// jobs.element();                  // NoSuchElementException
// jobs.remove();                   // NoSuchElementException

jobs.offer("reindex");
jobs.add("email-digest");

System.out.println(jobs.remove());  // reindex
System.out.println(jobs.poll());    // email-digest

Notice three things:

  • peek and poll can return null, so ArrayDeque forbids storing null elements.
  • offer reads better than add when queue capacity might matter.
  • remove and element are fine when an empty queue means your program has a bug.

The scenario version shows up often: "You are scheduling jobs FIFO. Which collection do you use?" If this is single-threaded or externally synchronized, I use ArrayDeque<Job> and call offer and poll. If the prompt says producers must wait when the queue is full and consumers must wait when it is empty, I switch to a bounded BlockingQueue, usually ArrayBlockingQueue or LinkedBlockingQueue.

In the real world

I have seen a background worker use LinkedList as a queue because the team remembered "linked list removes from the front cheaply". The queue held a few thousand jobs, and most CPU samples were not in business logic; they were allocation and pointer chasing. Replacing it with ArrayDeque removed one node allocation per job and made the worker's memory profile boring again.

03Deque as both queue and stack

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • ArrayDeque internals: head, tail and growth
  • BFS: the queue pattern everyone should know
  • Sliding window maximum: the monotonic deque
  • Choosing between ArrayDeque, LinkedList and BlockingQueue
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicQueues & deques: interview questions & scenarios
Further reading (6)