Back to Blog
Java

Java Queue peek: Inspect Head Without Removing

java queue peek: Learn how Java Queue.peek() inspects the head element without removing it, handles empty queues, and differs from poll() and element().

Java Queuepeek()Queue APIJava CollectionsLinkedListArrayDeque
Illustration of a Java Queue peek operation showing the head element being inspected without removal.

When working with a Java Queue, peek() is the method you call when you need to see the head element without removing it. Unlike poll(), which removes and returns the head, peek() leaves the queue unchanged. If the queue is empty, peek() returns null instead of throwing an exception. This makes java queue peek the safest way to inspect the front of a queue when you are not sure whether it contains elements.

What Queue.peek() Returns and When It Returns null

The peek() method is defined in the java.util.Queue interface and returns the head of the queue, or null if the queue is empty. The method signature is:

E peek()

The return type matches the generic type of the queue. For example, a Queue<String> returns a String. If the queue is empty, peek() returns null without throwing any exception. This is a key difference from the element() method, which throws NoSuchElementException when the queue is empty. The peek() method is part of the Collection framework and is available on all standard implementations such as LinkedList, ArrayDeque, and PriorityQueue.

peek() vs poll() vs element(): Choosing the Right Method

The Queue interface offers three methods that return the head element but behave differently. The table below summarizes the differences:

MethodRemoves HeadReturns on EmptyThrows on Empty
peek()NonullNo
poll()YesnullNo
element()No-NoSuchElementException

Use peek() when you want to inspect the head without modifying the queue. Use poll() when you want to retrieve and remove the head. Use element() only when you are certain the queue is non-empty and you want an exception to indicate a programming error if it is not.

Using peek() with Common Queue Implementations

The behavior of peek() is consistent across implementations, but the ordering and null handling differ. Here are examples with three common queues:

Queue<String> linkedListQueue = new LinkedList<>(); linkedListQueue.add("first"); linkedListQueue.add("second"); System.out.println(linkedListQueue.peek()); // prints "first"

LinkedList allows null elements, so peek() returning null could mean either an empty queue or a null head. ArrayDeque does not allow null elements, so null always means empty:

Queue<Integer> arrayDeque = new ArrayDeque<>(); arrayDeque.add(10); arrayDeque.add(20); System.out.println(arrayDeque.peek()); // prints 10

PriorityQueue orders elements by natural order or a custom comparator. peek() returns the smallest element according to that ordering:

Queue<Integer> priorityQueue = new PriorityQueue<>(); priorityQueue.add(30); priorityQueue.add(10); priorityQueue.add(20); System.out.println(priorityQueue.peek()); // prints 10

The head of a PriorityQueue is not necessarily the first inserted element; it is the element with the highest priority.

Common Mistakes When Calling peek()

A frequent mistake is assuming peek() never returns null. In a queue that allows null elements, such as LinkedList, a null return can mean the head is actually null. This ambiguity can lead to subtle bugs. Another mistake is using peek() to iterate over a queue; since peek() does not remove elements, calling it repeatedly always returns the same head. Some developers also confuse peek() with element(), expecting an exception on an empty queue. Understanding these differences prevents incorrect logic.

peek() in Concurrent and Blocking Queue Scenarios

For BlockingQueue implementations like ArrayBlockingQueue or LinkedBlockingQueue, peek() is non-blocking. It returns the head immediately, or null if the queue is empty. It does not wait for an element to become available, unlike take(). This makes peek() useful for checking queue state without blocking. However, in a multithreaded environment, peek() is not atomic with other operations. Another thread could remove the head between your peek() call and your next action. If you need a consistent view, you must synchronize externally or use methods like poll() that combine retrieval and removal atomically.

Performance and Runtime Cost of peek()

For standard queue implementations, peek() runs in constant time, O(1). LinkedList stores references to the head node, ArrayDeque uses a circular array, and PriorityQueue maintains the head at the root of a binary heap. In all cases, retrieving the head requires no traversal or modification. The cost is a single reference access. For custom queue implementations, the complexity depends on the underlying data structure. A queue backed by a List might require O(n) to find the head if it is not stored separately. Always check the implementation's documentation when performance is critical.

Handling Null Elements and Ambiguity

If your queue allows null elements, peek() returning null is ambiguous: it could mean the queue is empty or the head is null. To disambiguate, use isEmpty() before calling peek(). For queues that prohibit null, such as ArrayDeque and PriorityQueue, a null return unambiguously indicates an empty queue. If you need to store null values, consider using a sentinel object or a wrapper class to avoid the ambiguity.

Edge Cases: PriorityQueue Ordering and Custom Comparators

PriorityQueue uses a comparator to determine the head. If you provide a custom comparator, peek() returns the element that the comparator considers smallest. For example:

Queue<String> pq = new PriorityQueue<>(Comparator.reverseOrder()); pq.add("apple"); pq.add("banana"); System.out.println(pq.peek()); // prints "banana"

The ordering is fixed at construction time. If the queue contains elements whose comparison changes over time (e.g., mutable objects), the head may not reflect the current ordering. peek() does not trigger reordering; only add() and poll() do. This is an important edge case when using PriorityQueue with mutable objects.

When to Use peek() Instead of Checking isEmpty() First

A common pattern is to check isEmpty() before calling peek(). This is necessary when the queue can contain null elements. For queues that do not allow null, you can use peek() != null as a concise emptiness check. However, this pattern is less readable and can be misleading if the queue implementation changes. The clearest approach is to call isEmpty() first, then peek(). This makes the intent explicit and avoids ambiguity. Use peek() directly when you are only interested in the head and are prepared to handle a null return as an empty queue.

java queue peek: Practical Usage and Code Examples | RYUSLOG DEV