🗃️ Collections Framework · Intermediate

Queue, Deque & ArrayDeque in Java

FIFO/LIFO, offer/poll/peek vs add/remove/element.

🧩 The mysteryOne class can act as a supermarket checkout line AND a stack of plates. Meet ArrayDeque, the most useful collection you might not be using yet.

The waiting line

A **Queue processes elements in order, usually first-in, first-out (FIFO). offer adds to the tail, poll takes the head, peek** looks at the head without removing it.

Queue<String> q = new ArrayDeque<>();
q.offer("a");   // [a]
q.offer("b");   // [a, b]
q.peek();       // "a" (still there)
q.poll();       // "a" → [b]

Two flavours of every operation

Each operation comes in two flavours. One throws when it can't do its job; the other returns a special value like null. On an empty queue, poll() gives null but remove() throws **NoSuchElementException**.

// throws        returns special value
add(x)          offer(x)  // insert
remove()        poll()    // take head
element()       peek()    // read head
🔮 Predict it

Your turn

What does this print?

Queue<String> q = new ArrayDeque<>();
q.offer("x");
q.offer("y");
q.offer("z");
String out = q.poll() + q.peek() + q.size();
System.out.println(out);
  1. xy2
  2. xx3
  3. xy3
Show the answer

FIFO: poll() removes x, peek() reads the new head y without removing it, leaving 2 elements.

Deque = queue + stack

A **Deque (double-ended queue) works at both ends. Used as a stack**, push, pop and peek all work at the front. pop() on an empty deque throws NoSuchElementException. When printed, a deque shows front to back.

Deque<String> d = new ArrayDeque<>();
d.offerLast("a");  // queue style: [a]
d.push("z");       // stack style: [z, a]
d.pop();           // "z" (the front)
🔮 Predict it

Stack it up

What does this print?

Deque<String> stack = new ArrayDeque<>();
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack.pop() + " " + stack);
  1. a [b, c]
  2. c [b, a]
  3. c [a, b]
Show the answer

Each push goes on the front: [c, b, a]. pop() takes the front, c, and the deque prints front to back: [b, a].

⚠️ The trap

No nulls allowed

**ArrayDeque rejects null** with NullPointerException. It's on purpose: poll() and peek() use null to mean "empty", so a stored null would be ambiguous.

Deque<String> d = new ArrayDeque<>();
d.poll();      // null: empty, fine
d.offer(null); // NullPointerException
💼 In the real world

Queues everywhere

Breadth-first search, job queues, undo stacks, browser history, parsing brackets: all ArrayDeque territory. Its Javadoc notes it is likely faster than Stack used as a stack and faster than LinkedList used as a queue, which is why it's the default choice.

Key takeaways

  1. Queue: offer (add to tail), poll (take head), peek (look at head)
  2. Throwing versions: add, remove, element
  3. Stack via Deque: push, pop, peek — all at the front
  4. ArrayDeque doesn't allow null elements

💡 A Deque is a train you can board or leave from either end.

🤯 Did you know?

ArrayDeque is a circular buffer: head and tail indexes wrap around the end of its internal array, so adding at the front never has to shift anything.

Practice questions

What does this print?

Queue<String> q = new ArrayDeque<>();
q.offer("a");
q.offer("b");
q.offer("c");
System.out.println(q.poll() + q.peek() + q.size());
  1. ab2
  2. aa3
  3. ca2
  4. ab3
Check your answer

ab2. FIFO: poll removes "a", peek reads the new head "b" without removing it, leaving 2 elements.

What does this print?

Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.pop() + " " + stack);
  1. 1 [2, 3]
  2. 3 [1, 2]
  3. 3 [2, 1]
  4. 1 [3, 2]
Check your answer

3 [2, 1]. push adds at the front, so the deque is [3, 2, 1]. pop removes the front (3). ArrayDeque prints from front to back: [2, 1].

Next: a queue where the most urgent item always jumps the line, even though its printout looks like nonsense.