Attic
CollectionsQueues & Deques

Overview

FIFO, LIFO, and priority queue implementations, method families, and quick selection guide

Java's Queue<E> and Deque<E> structure elements around head and tail access. They provide multiple concrete implementations and parallel method families to handle boundary conditions cleanly.

Queue<E> (Core FIFO & Priority Contract)
├── ArrayDeque ──────➔ Contiguous circular array (Default FIFO Queue & LIFO Stack)
├── LinkedList ──────➔ Doubly-linked nodes (Use for nulls or O(1) node removal)
├── PriorityQueue ───➔ Dynamic binary heap (Min/Max priority ordering)
└── BlockingQueue ───➔ Thread-safe concurrent queues (Producer-Consumer pipelines)

Queue Implementations: When to Use Which

ImplementationUnderlying StructureHead / Tail OpsWhen to Use (Best For)When to Avoid
ArrayDequeCircular dynamic arrayO(1)Default choice for FIFO queues, LIFO stacks, and sliding windowsNeed priority sorting or multi-thread safety
LinkedListDoubly-linked discrete nodesO(1)Strictly require storing null or need O(1) node removal via external referenceGeneral queues/stacks (high GC churn, poor CPU cache locality)
PriorityQueueDynamic binary heap arrayO(log n)Priority scheduling, top-K selection, continuous min/maxNeed strict FIFO arrival order
BlockingQueueThread-safe concurrent bufferO(1)Multi-threaded producer-consumer queues (ArrayBlockingQueue, etc.)Single-threaded apps (locking overhead)
Quick Decision Rule:
├── Need Priority / Sorted Order? ─➔ PriorityQueue
├── Multi-threaded Producers? ────➔ BlockingQueue
└── Standard FIFO Queue or Stack? ─➔ ArrayDeque (almost always better than LinkedList)

Method Types: Why Dual Methods and When to Use Which

Queue operations encounter two normal boundary conditions:

  • Full queues (capacity limit reached on bounded queues)
  • Empty queues (reading from an empty queue)

To avoid forcing costly try/catch exceptions for standard flow control, Java defines two parallel method families for every operation:

Core OperationSafe Method (Returns Value)Strict Method (Throws Exception)Return TypeWhen to Use Which
Insert / Enqueueoffer(e) ➔ returns false if fulladd(e) ➔ throws IllegalStateExceptionbooleanUse offer for bounded buffers; use add if a full queue indicates an illegal state
Remove / Dequeuepoll() ➔ returns null if emptyremove() ➔ throws NoSuchElementExceptionEUse poll for consumer loops (while (!q.isEmpty())); use remove when head must exist
Examine / Inspectpeek() ➔ returns null if emptyelement() ➔ throws NoSuchElementExceptionEUse peek to safely inspect; use element when an empty queue is a critical bug

Quick Rule: Always default to the Safe Family (offer, poll, peek) for normal control flow and consumer loops. Reserve the Strict Family (add, remove, element) strictly for asserting state invariants where unexpected capacity or emptiness indicates a program bug.


Queue & Deque Toolkit Reference

The primary operational methods across Queue<E> and Deque<E>:

MethodParametersReturn TypeRole / InterfaceFailure Behavior
offer(e)(E e)booleanQueue (Enqueue)Returns false if capacity full
poll()noneEQueue (Dequeue)Returns null if queue empty
peek()noneEQueue (Inspect)Returns null if queue empty
add(e)(E e)booleanQueue (Strict insert)Throws IllegalStateException if full
remove()noneEQueue (Strict remove)Throws NoSuchElementException if empty
element()noneEQueue (Strict inspect)Throws NoSuchElementException if empty
offerFirst(e)(E e)booleanDeque (Head insert)Returns false if capacity full
offerLast(e)(E e)booleanDeque (Tail insert)Returns false if capacity full
pollFirst()noneEDeque (Head remove)Returns null if empty
pollLast()noneEDeque (Tail remove)Returns null if empty
peekFirst()noneEDeque (Head inspect)Returns null if empty
peekLast()noneEDeque (Tail inspect)Returns null if empty
push(e)(E e)voidDeque (LIFO Stack push)Inserts at head (addFirst)
pop()noneEDeque (LIFO Stack pop)Removes from head (removeFirst); throws if empty
isEmpty()nonebooleanCollectiontrue if size is 0
size()noneintCollectionTotal active elements

Detailed Guides

On this page