Back to Blog
Java

Java ArrayDeque pollFirst and pollLast: Usage and Behavior

java arraydeque pollfirst polllast: Understand Java ArrayDeque's pollFirst and pollLast methods: their return behavior, differences from removeFirst, and practical usa...

ArrayDequeJava CollectionsDequeQueuepollFirstpollLast
Diagram showing ArrayDeque with pollFirst and pollLast removing elements from both ends.

java arraydeque pollfirst polllast requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

The ArrayDeque class in Java provides a resizable-array implementation of the Deque interface. Among its many methods, pollFirst() and pollLast() are commonly used to retrieve and remove elements from the front and back of the deque. This article focuses on how these methods behave, how they differ from similar methods like removeFirst(), and where they fit in real-world code.

What Are pollFirst and pollLast in ArrayDeque?

pollFirst() removes and returns the first element of the deque, while pollLast() removes and returns the last element. Both methods return null if the deque is empty. This behavior is defined in the Deque interface and implemented by ArrayDeque.

Deque<String> deque = new ArrayDeque<>(); deque.add("first"); deque.add("second"); deque.add("third"); String head = deque.pollFirst(); // returns "first" String tail = deque.pollLast(); // returns "third"

After these operations, the deque contains only "second". The methods mutate the deque by removing the element they return. If the deque is empty, both methods return null without throwing an exception.

pollFirst vs removeFirst: Return Behavior on Empty Deque

The most important distinction is how the methods handle an empty deque. pollFirst() and pollLast() return null, whereas removeFirst() and removeLast() throw NoSuchElementException. This makes the poll variants safer in scenarios where the deque might be empty and you want to avoid exception handling.

Deque<String> emptyDeque = new ArrayDeque<>(); String value = emptyDeque.pollFirst(); // null, no exception String value2 = emptyDeque.removeFirst(); // throws NoSuchElementException

Choosing between these depends on whether an empty deque is a normal condition or an exceptional one. In a producer–consumer pattern where the queue is frequently empty, pollFirst() is the natural choice. If an empty deque indicates a programming error, removeFirst() makes that failure explicit.

Using pollFirst and pollLast for Queue and Stack Operations

ArrayDeque can be used as a queue (FIFO) or a stack (LIFO). The poll methods align with these use cases:

  • Queue: addLast() to enqueue, pollFirst() to dequeue.
  • Stack: addFirst() to push, pollFirst() to pop.
// Queue usage ArrayDeque<Integer> queue = new ArrayDeque<>(); queue.addLast(10); queue.addLast(20); Integer next = queue.pollFirst(); // 10 // Stack usage ArrayDeque<Integer> stack = new ArrayDeque<>(); stack.addFirst(1); stack.addFirst(2); Integer top = stack.pollFirst(); // 2

For stack operations, pollLast() can also be used if you push with addLast(). The key is to be consistent. The ArrayDeque class is often preferred over Stack for single-threaded code because it is faster and does not carry the legacy synchronization overhead of Stack.

Performance and Memory Characteristics of ArrayDeque

The ArrayDeque is backed by a dynamically resizing array. This gives it amortized constant-time performance for addFirst, addLast, pollFirst, and pollLast. The array grows automatically when capacity is exceeded, which involves copying elements. However, the amortized cost remains O(1) per operation.

Memory-wise, ArrayDeque uses a contiguous array, which is more cache-friendly than a linked structure. It also avoids the per-node object overhead of LinkedList. For most use cases, ArrayDeque outperforms LinkedList in both time and memory, especially when the deque size is large.

One limitation is that ArrayDeque does not allow null elements. Attempting to add null throws NullPointerException. This is a deliberate design choice because pollFirst() and pollLast() use null to indicate an empty deque. If you need to store null values, you must use a different Deque implementation like LinkedList.

Thread Safety and Concurrent Access

ArrayDeque is not thread-safe. If multiple threads access the same instance concurrently, external synchronization is required. The pollFirst() and pollLast() methods are not atomic. In a multi-threaded environment, you should use a thread-safe Deque implementation such as ConcurrentLinkedDeque or wrap the ArrayDeque with Collections.synchronizedDeque().

Deque<String> safeDeque = Collections.synchronizedDeque(new ArrayDeque<>());

Even with synchronization, compound operations like "poll if not empty" need careful coordination. For a truly non-blocking concurrent queue, ConcurrentLinkedDeque is a better fit. It provides lock-free access and does not permit null elements either.

Practical Example: Task Processing with pollFirst

A common pattern is a work queue where tasks are processed by one or more workers. Using pollFirst() allows a worker to retrieve a task without throwing if the queue is empty.

ArrayDeque<Runnable> tasks = new ArrayDeque<>(); // ... tasks are added via tasks.addLast(runnable) Runnable task; while ((task = tasks.pollFirst()) != null) { task.run(); }

This loop terminates when the deque becomes empty. The pollFirst() return value is checked for null to stop the loop. This is a clean way to drain a deque without relying on exceptions or separate size checks.

If you need to process the last element first, you would use pollLast() in a similar manner. This is useful for stack-like processing where the most recently added item should be handled first.

When to Choose ArrayDeque Over LinkedList

ArrayDeque is the recommended implementation of Deque for most single-threaded scenarios. It offers better performance due to its array backing and lower memory overhead. LinkedList implements both List and Deque, so it is useful when you need indexed access or the ability to store null elements. However, for pure deque operations, ArrayDeque is almost always the better choice.

CharacteristicArrayDequeLinkedList
Underlying structureResizable arrayDoubly linked list
Null elementsNot allowedAllowed
Indexed accessNot supportedSupported (O(n))
Memory overheadLower (contiguous array)Higher (per-node objects)
Best forQueue/stack, single-threadedList + deque, null elements

The decision comes down to whether you need list-specific features. If your code only uses deque operations, ArrayDeque is the safer, faster default. The pollFirst() and pollLast() methods are an integral part of that efficiency, providing a simple and reliable way to consume elements from either end.

java arraydeque pollfirst polllast: Practical Usage and Code | RYUSLOG DEV