The Queue interface offers two families of operations for inserting, removing, and inspecting elements. What are they, and how do they differ in behavior on failure?
answer
- Three actions x two failure styles = six methods
- add/remove/element throw; offer/poll/peek return false/null
- poll/peek return null on empty; remove/element throw NoSuchElementException
- add throws IllegalStateException when bounded queue full; offer returns false
- null returns clash with nullable elements -> most queues forbid null
basics
~10 sQueue has two sets of methods. add/remove/element throw an exception when they can't do the operation. offer/poll/peek instead return a special value (false or null) and don't throw.
solid answer
~40 sQueue defines six core operations in two parallel families. The exception-throwing family is add (insert), remove (remove head), and element (look at head); each throws if it can't act: add throws IllegalStateException when a bounded queue is full, while remove and element throw NoSuchElementException on an empty queue. The special-value family is offer (insert), poll (remove head), and peek (look at head); offer returns false when it can't insert, and poll and peek return null on an empty queue instead of throwing. Choose the special-value methods when emptiness or fullness is a normal, expected condition you want to test for, and the throwing methods when failure is genuinely exceptional. Note that null returns are ambiguous if the queue is allowed to hold null elements, which is one reason most Queue implementations forbid null.
code
java · 13 linesQueue<String> q = new ArrayDeque<>();
q.offer("a"); // true
// special-value family: safe drain
String head;
while ((head = q.poll()) != null) {
System.out.println(head);
}
// now empty
System.out.println(q.peek()); // null (no throw)
// q.element(); // would throw NoSuchElementException
// q.remove(); // would throw NoSuchElementExceptiongo deeper
Can name the two families and state that one throws while the other returns false/null.
Names the exact exceptions (IllegalStateException for full, NoSuchElementException for empty) and the special return values, and knows the null-forbidding rationale.
Articulates the design intent (expected vs exceptional failure), recommends offer for bounded queues, and writes idiomatic poll-based drain loops.
Frames the dual API as a deliberate control-flow contract, discusses how it interacts with bounded/concurrent implementations (back-pressure via offer with timeout) and the null-ambiguity invariant across the collection hierarchy.
## What a Queue is A **Queue** is a collection designed to hold elements before they are processed, typically in **FIFO** (first-in, first-out) order: the element that has been waiting longest is the next one removed. Think of a line at a checkout. In Java, `java.util.Queue<E>` is an interface that extends `Collection<E>`. ## The three logical operations Every queue supports three logical actions: - **Insert** an element (add it, usually at the tail). - **Remove** an element (take the head off). - **Examine** an element (look at the head without removing it). ## Why there are two method families For each of those three actions, Java provides **two** methods that behave differently when the operation **cannot** be performed (the queue is empty for remove/examine, or full for insert in a capacity-bounded queue). This gives six methods total: | Action | Throws on failure | Returns special value on failure | |---|---|---| | Insert | `add(e)` | `offer(e)` | | Remove | `remove()` | `poll()` | | Examine | `element()` | `peek()` | ### Exception-throwing family (add / remove / element) - `add(e)`: inserts; returns `true` on success. If a **capacity-restricted** queue is full, it throws **`IllegalStateException`**. (Inherited from `Collection.add`.) - `remove()`: removes and returns the head. If the queue is **empty**, throws **`NoSuchElementException`**. - `element()`: returns the head **without** removing it. If empty, throws **`NoSuchElementException`**. Use these when being unable to act is a *bug* — you expect the element to be there, and a crash is the right outcome. ### Special-value family (offer / poll / peek) - `offer(e)`: inserts; returns `true` on success, **`false`** if it can't insert (e.g. a bounded queue is full). It does not throw for the ordinary 'full' case, so it is the right choice for bounded queues. - `poll()`: removes and returns the head, or returns **`null`** if the queue is empty. - `peek()`: returns the head without removing it, or **`null`** if the queue is empty. Use these when emptiness/fullness is a *normal, expected* state you want to branch on, e.g. a draining loop: `while ((item = queue.poll()) != null) { process(item); }`. ## The null ambiguity Because `poll()` and `peek()` use `null` to mean 'nothing there', storing an actual `null` element would make their results ambiguous. For this reason most implementations (`ArrayDeque`, `LinkedList` as a queue's contract, `PriorityQueue`, the concurrent queues) **forbid null elements** and throw `NullPointerException` if you try to insert one. (`LinkedList` technically permits nulls because it predates the contract, but relying on that is a trap.) ## How to choose - Bounded/back-pressure-aware producer: prefer `offer` (test the boolean) over `add` (which throws). - Pulling work until exhausted: prefer `poll`/`peek` and check for `null`. - Invariant 'this must not be empty': `remove`/`element` make the failure loud. This dual API is a deliberate design so callers can pick *control flow via return value* or *control flow via exceptions* depending on whether failure is expected or exceptional.
- Why do most Queue implementations forbid null elements?Because poll() and peek() return null to signal an empty queue. If null were a legal element, a null return would be ambiguous (was it an element or emptiness?), so implementations like ArrayDeque and PriorityQueue throw NullPointerException on null insertion.
- Which method would you use to drain a queue in a loop and why?poll(), because it returns null on empty, letting you write while ((x = q.poll()) != null) without catching exceptions for the normal termination case.
saying these in an interview costs you the question
- Saying remove() returns null on empty (it throws NoSuchElementException)
- Claiming both families throw, or both return null
- Thinking add() returns false when full (it throws; offer() returns false)
- Assuming you can safely store null in a Queue and still rely on poll/peek