Java > Java Collections Framework > Queue and Deque > Deque Interface (ArrayDeque)

ArrayDeque Example: Adding and Removing Elements

This snippet demonstrates how to add and remove elements from an ArrayDeque, showcasing its LIFO (Last-In-First-Out) and FIFO (First-In-First-Out) capabilities.

Core Implementation

This code initializes an ArrayDeque and demonstrates adding elements to both the head (using addFirst()) and the tail (using addLast()). It also shows how to remove elements from both ends using removeFirst() and removeLast(). The output demonstrates the order in which elements are added and removed.

import java.util.ArrayDeque;

public class ArrayDequeExample {
    public static void main(String[] args) {
        // Creating an ArrayDeque
        ArrayDeque<String> deque = new ArrayDeque<>();

        // Adding elements to the head (front)
        deque.addFirst("First");
        deque.addFirst("Second");
        deque.addFirst("Third");

        // Adding elements to the tail (end)
        deque.addLast("Fourth");
        deque.addLast("Fifth");

        System.out.println("Deque after additions: " + deque);

        // Removing elements from the head
        String firstElement = deque.removeFirst();
        System.out.println("Removed from head: " + firstElement);

        // Removing elements from the tail
        String lastElement = deque.removeLast();
        System.out.println("Removed from tail: " + lastElement);

        System.out.println("Deque after removals: " + deque);
    }
}

Concepts Behind the Snippet

ArrayDeque is a resizable-array implementation of the Deque interface. It provides constant-time performance for adding and removing elements from both ends. It is particularly useful when you need both queue (FIFO) and stack (LIFO) functionality in a single data structure. The key methods used are addFirst(), addLast(), removeFirst(), and removeLast().

Real-Life Use Case

A common use case for ArrayDeque is in implementing a task scheduling system where tasks can be added to the front for urgent processing (priority queue) or to the back for normal processing. It is also used in implementing undo/redo functionality in applications where actions need to be tracked and reversed.

Best Practices

  • Avoid using null elements in an ArrayDeque, as it can lead to unexpected behavior and NullPointerException.
  • Consider the initial capacity of the ArrayDeque if you have an estimate of the number of elements it will hold to avoid frequent resizing.
  • Use offerFirst, offerLast, pollFirst and pollLast when dealing with capacity-restricted deques. They provide a way to insert and remove without throwing an exception.

Interview Tip

Be prepared to explain the difference between ArrayDeque and LinkedList as implementations of the Deque interface. ArrayDeque is generally faster for most operations due to its array-based implementation, but LinkedList offers better memory efficiency when dealing with a large number of elements that are frequently inserted or removed from the middle.

When to Use Them

Use ArrayDeque when you need a fast and efficient implementation of a double-ended queue, especially when you know the approximate size of the queue beforehand. It is preferable over LinkedList for most queue and stack operations due to its superior performance.

Memory Footprint

ArrayDeque's memory footprint can be larger than LinkedList, especially if the initial capacity is set too high. However, its contiguous memory allocation leads to better cache locality and faster performance. The memory usage grows dynamically as elements are added, but resizing the array can be a relatively expensive operation.

Alternatives

The primary alternative to ArrayDeque is LinkedList, which also implements the Deque interface. LinkedList is a better choice if you need to perform frequent insertions or deletions in the middle of the queue or if memory usage is a primary concern. Other alternatives include ConcurrentLinkedDeque for thread-safe operations.

Pros

  • Fast and efficient for adding and removing elements from both ends (O(1) complexity).
  • Array-based implementation provides better cache locality.
  • Resizable array, allowing it to grow dynamically.

Cons

  • Resizing the array can be an expensive operation.
  • Can have a larger memory footprint than LinkedList if not managed carefully.
  • Not thread-safe (use ConcurrentLinkedDeque for thread-safe operations).

FAQ

  • What is the difference between addFirst() and offerFirst() in ArrayDeque?

    addFirst() throws an IllegalStateException if the deque is full (if it's a capacity-restricted deque), while offerFirst() returns false in the same situation. offerFirst() is generally preferred when dealing with capacity-restricted deques.
  • Is ArrayDeque thread-safe?

    No, ArrayDeque is not thread-safe. If you need a thread-safe deque, use ConcurrentLinkedDeque from the java.util.concurrent package.
  • How does ArrayDeque handle null elements?

    ArrayDeque does not allow null elements. Attempting to add a null element will result in a NullPointerException.