Java Collections Framework – The Queue Interface

In this guide, we will learn about the Queue interface, its methods, and its implementation classes.

Important Key Points About  Queue Interface

The Java Queue interface is part of the Java Collections Framework, specifically under java.util package, and it presents some key characteristics: 

FIFO: 

The Queue follows the First-In-First-Out algorithm. It means that the elements get added at the end (rear) and are removed from the beginning (front) of the Queue. 

Insertion and Removal Operations: 

The Queue interface supports all basic operations such as insert, remove, and examine. For insertion, we can use the add(E e) or offer(E e) methods. For removing an element, remove() and poll() are used. To examine or retrieve an element, element() and peek() are available. 

Exception throwing and Non-Exception throwing methods: 

Each operation in a queue has two methods, one that throws an exception when the operation fails and the other returns a special value (null or false, depending on the operation). For example, add(E e) throws an IllegalStateException if no space is currently available and offer(E e) simply returns false in the same scenario. 

Blocking Queues: 

Java provides the BlockingQueue interface, which extends Queue. BlockingQueues have features that allow threads to wait when they try to dequeue an empty queue or enqueue items to a full queue. This feature makes it excellent for inter-thread communication. 

PriorityQueue: 

It's a Queue data structure implementation where elements are dequeued in priority order (not just FIFO). This priority can be set via a comparator provided at Queue construction time. 

Null Elements: 

Some Queue implementations (LinkedList) permit null elements, but others like PriorityQueue do not. 

Usage in real-world applications: 

Queue interface is used widely in real-world applications like concurrent programming, algorithms, and data structure implementation, etc. 

Thread Safety: 

Unless otherwise mentioned (as in ConcurrentLinkedQueue and BlockingQueue implementations), Queues are not thread-safe. You have to manually synchronize concurrent access to a queue in a multi-threaded environment. 

The Queue Interface Methods

Each Queue method exists in two forms:
These methods throw an exception if the operation fails.
  • boolean add(E e) - This method inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning true upon success and throwing an IllegalStateException if no space is currently available.
  • E element() - This method retrieves, but does not remove, the head of this queue.
  • E remove() - This method retrieves and removes the head of this queue.
These methods return a special value if the operation fails (either null or false, depending on the operation).
  • boolean offer(E e) - This method inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions.
  • E peek() - This method retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.
  • E poll() - This method retrieves and removes the head of this queue, or returns null if this queue is empty.

The Queue Interface Class Diagram

The below diagram shows a list of methods the Queue interface provides.

The Queue Interface Hierarchy Diagram

The Queue interface extends the Collection interface and provides provide additional insertion, removal, and inspection operations.

The Queue Interface with Its LinkedList Implementation Class Example 

Creating a Queue using the LinkedList implementation class and performing basic operations like Enqueue and Dequeue:
import java.util.LinkedList;
import java.util.Queue;

/**
 * Demonstrate Queue interface methods with LinkedList implementation.
 * @author javaguides.net
 *
 */
public class QueueExample {
    public static void main(String[] args) {
        // Create and initialize a Queue using a LinkedList
        Queue<String> elementQueue = new LinkedList<>();

        // Adding new elements to the Queue (The Enqueue operation)
        elementQueue.add("element1");
        elementQueue.add("element2");
        elementQueue.add("element3");
        elementQueue.add("element4");

        System.out.println("WaitingQueue : " + elementQueue);

        // Removing an element from the Queue using remove() (The Dequeue operation)
        // The remove() method throws NoSuchElementException if the Queue is empty
        String name = elementQueue.remove();
        System.out.println("Removed from WaitingQueue : " + name + " | New WaitingQueue : " + elementQueue);

        // Removing an element from the Queue using poll()
        // The poll() method is similar to remove() except that it returns null if the Queue is empty.
        name = elementQueue.poll();
        System.out.println("Removed from WaitingQueue : " + name + " | New WaitingQueue : " + elementQueue);
    }
}
Output:
WaitingQueue : [element1, element2, element3, element4]
Removed from WaitingQueue : element1 | New WaitingQueue : [element2, element3, element4]
Removed from WaitingQueue : element2 | New WaitingQueue : [element3, element4]

Queue Interface Methods - isEmpty(), size(), element(), peek()

Let's demonstrate Queue interface methods - isEmpty(), size(), element(), peek() with examples.
  • Check if a Queue is empty.
  • Find the size of a Queue.
  • Search for an element in a Queue.
  • Get the element at the front of the Queue without removing it.
import java.util.LinkedList;
import java.util.Queue;

/**
 * Demonstrate Queue interface methods with LinkedList implementation.
 * @author javaguides.net
 *
 */

public class QueueSizeSearchFrontExample {
    public static void main(String[] args) {
        Queue<String> elementQueue = new LinkedList<>();

        elementQueue.add("element1");
        elementQueue.add("element2");
        elementQueue.add("element3");
        elementQueue.add("element4");

        System.out.println("WaitingQueue : " + elementQueue);

        // Check is a Queue is empty
        System.out.println("is waitingQueue empty? : " + elementQueue.isEmpty());

        // Find the size of the Queue
        System.out.println("Size of waitingQueue : " + elementQueue.size());

        // Check if the Queue contains an element
        String name = "Johnny";
        if(elementQueue.contains(name)) {
            System.out.println("WaitingQueue contains " + name);
        } else {
            System.out.println("Waiting Queue doesn't contain " + name);
        }

        // Get the element at the front of the Queue without removing it using element()
        // The element() method throws NoSuchElementException if the Queue is empty
        String firstElementInTheWaitingQueue =  elementQueue.element();
        System.out.println("Waiting Queue (element()) : " + firstElementInTheWaitingQueue);

        // Get the element at the front of the Queue without removing it using peek()
        // The peek() method is similar to element() except that it returns null if the Queue is empty
        firstElementInTheWaitingQueue = elementQueue.peek();
        System.out.println("Waiting Queue : " + firstElementInTheWaitingQueue);

    }
}
Output:
WaitingQueue : [element1, element2, element3, element4]
is waitingQueue empty? : false
Size of waitingQueue : 4
Waiting Queue doesn't contain Johnny
Waiting Queue (element()) : element1
Waiting Queue : element1

Iterating over a Queue in Java

The example in this section shows various ways of iterating over a Queue:
  • Iterate over a Queue using Java 8 forEach() method.
  • Iterate over a Queue using iterator().
  • Iterate over a Queue using iterator() and Java 8 forEachRemaining() method.
  • Iterate over a Queue using a simple for-each loop.
  • The iteration order in a Queue is the same as the insertion order.
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

/**
 * Iterate over Queue with different approaches.
 * @author javaguides.net
 *
 */

public class IterateOverQueueExample {
    public static void main(String[] args) {
        Queue<String> elementsQueue = new LinkedList<>();

        elementsQueue.add("element1");
        elementsQueue.add("element2");
        elementsQueue.add("element3");
        elementsQueue.add("element4");

        System.out.println("=== Iterating over a Queue using Java 8 forEach() ===");
        elementsQueue.forEach(name -> {
            System.out.println(name);
        });

        System.out.println("\n=== Iterating over a Queue using iterator() ===");
        Iterator<String> elementQueueIterator = elementsQueue.iterator();
        while (elementQueueIterator.hasNext()) {
            String name = elementQueueIterator.next();
            System.out.println(name);
        }

        System.out.println("\n=== Iterating over a Queue using iterator() and Java 8 forEachRemaining() ===");
        elementQueueIterator = elementsQueue.iterator();
        elementQueueIterator.forEachRemaining(name -> {
            System.out.println(name);
        });

        System.out.println("\n=== Iterating over a Queue using simple for-each loop ===");
        for(String name: elementsQueue) {
            System.out.println(name);
        }
    }
}
Output:
=== Iterating over a Queue using Java 8 forEach() ===
element1
element2
element3
element4

=== Iterating over a Queue using iterator() ===
element1
element2
element3
element4

=== Iterating over a Queue using iterator() and Java 8 forEachRemaining() ===
element1
element2
element3
element4

=== Iterating over a Queue using simple for-each loop ===
element1
element2
element3
element4

Queue Interface Implementations

General purpose implementation class:

References

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/util/Queue.html

Comments