Has Java taken over the world of technology for applications?
Perhaps not, but with a population of between 8-10 million Java developers worldwide, the language certainly owns more than a fair share of the market.
Portability is a major factor in Java’s popularity. You can develop powerful applications with the Java Development Kit (JDK) for any device that supports the Java Virtual Machine (JVM) environment – which includes a population of devices now numbering in the billions.
In fact, Java applications are running on everything from enterprise mainframes to laptop computers. They are abundant on smartphones and tablets, and even found powering smart devices such as televisions and home appliances.
With all the functionality Java offers developers, one function that is commonly utilized is the Java Queue Interface. It’s important to understand the purpose and proper use of Java’s queueing process, to use it effectively in your applications.
What Is the Java Queue Interface?
A queue is a collection of data elements that are waiting to be processed. You experience this phenomenon almost daily:
Waiting in line at the supermarket
Lining up at a fast-food drive-thru window
Waiting for your turn to ride at an amusement park
Queues are essentially a first-in, first-out (FIFO) method of handling data and transactions. You process the next element in line and remove it, while adding new elements at the end of the queue.
Java implements this same concept in the creation and processing of data with a FIFO methodology in managing data through the Java queue interface.
This simple guide to understanding the Java Queue Interface will provide insight into how the queues are created and used in application design and execution.
Types of Java Queues
The Java.util package provides multiple types (or classes) of queues for use in your applications, each with its own set of characteristics and functionality. The most commonly-used classes are:
PriorityQueue – based on the heap data structure, priority queue elements are ordered depending on the order that you specified when the queue is constructed.
You can explicitly define ordering, or utilize the natural ordering of the elements.
With the Priority Queue, the queue can be ordered as you define in its construction, but the queue will still be accessed front to back with respect to its ordering.
LinkedList Queue – utilizes typical FIFO ordering for queue operations
ArrayBlockingQueue – this is an array where the first and last elements in the queue or array are considered to be adjacent, making the structure logically circular. Indexes are incremented for the head and tail of the array as elements are added or removed.
As a queue, elements do not need to be shifted when the head of the queue is removed, making this queue class a better choice than an array.
ArrayBlockingQueue has a predefined capacity that you specify when constructing this class of queue.
Neither Priority or Linked List queues provide a thread-safe implementation, such that use of Java queue interfaces must take this attribute into account when utilizing these classes in applications.
Java supports the use of a data structure by multiple concurrent programs, known as multi-threaded applications. This can present challenges for data integrity, where multiple threads access, insert, or remove data at the same time.
Applications are referred to as thread-safe when multiple threads can safely access the data structures at the same time without risk of data corruption, such as one thread removing data as another thread attempts to update the same element.
Queue types that fit the requirement for thread-safe operation of Java queue implementation are blocking queues such as PriorityBlockingQueue and ArrayBlockingQueue.
Java Queue Characteristics
Using the Java queue interface in your applications, you should understand the basic rules and characteristics of queue data structures:
Queues are generally utilized to insert elements at the end of the queue and remove from the head of the structure (FIFO – remember your supermarket line).
Queues in the java.utl.concurrent package are bounded queues
Java queues support all Collection interface methods (more on that later)
Blocking queues provide thread-safe implementations
Queues in the java.utl package are unbounded queues
Queues only support insert at the tail and removal at the head (exception is Deques, which support removal and insert at both ends)
Adding an element to the end of a queue is referred to as an Enqueue operation. Removing an element is termed a Dequeue.
Java Methods for Processing Queues
Since Java queue implementations are a Collection subtype, they support a full scope of methods for processing queue elements:
add() – insert elements at the end of the queue (or in the order specified, in the case of priority queue)
offer() – adds an element to the end of the queue, returning a Boolean value to verify whether or not the insert was successful
peek() – allows you to view the head element in the queue. The element is not removed. If the queue is empty, a null value is returned
push() – adds an element to the head of the queue
pop() – returns the first element from the head and removes it
element() – very similar to the action of the peek method, except when the queue is empty, the NoSuchElementException is thrown.
poll() – returns the head element in the queue, removing it. An empty queue results in a null value
remove() – returns and removes the head element as poll does, but returns the NoSuchElementException for an empty queue
When implementing a Deque interface, methods available include:
addFirst – insert an element at the head of the queue
removeFirst – return and remove the head of the queue
addLast – insert an element at the end of the queue
removeLast – return and remove the last element in the queue
getFirst – retrieve the first element in the queue
getLast – retrieve the last element in the queue
offerFirst – adds an element to the front of the queue with Boolean response
offerLast – adds an element to the tail of the queue with Boolean response
It’s important to note the difference in the use of the peek method which will retrieve the next element in the queue, without removing the element, as opposed to the poll method, which retrieves the same element, but also removes it.
Other significant differences between methods are simply the exception conditions that are returned from the method, such as:
add() and offer() – both add or enqueue the element to the queue, but where an unsuccessful operation will return an exception from add, the same result from offer will return Boolean false.
Similar differences exist between other methods, as with remove and poll, or peek and element.
You can utilize iteration to process all elements in a Java queue easily and efficiently. There are several options for using iteration with a Java queue:
Iterate the queue utilizing iterator()
Utilize the Java8 forEach() method
Iterate over the queue combining the use of iterator() and Java8 forEachRemaining() method
Iterate over a queue with a forEach loop
Iteration sequence will be the same as the queue insertion order. If you need to iterate from the end of the queue to the front, simply use the descendingIterator function to traverse the queue in reverse order.
There are additional classes of queues that can be utilized for their specific characteristics:
Transfer Queue – this is a blocking queue that you can use when you want the application to wait after adding an element to the queue until another thread has retrieved that element. This is an unbounded queue.
Deque – pronounced “deck”, this interface can be implemented as a double-ended queue, where elements can be inserted or, retrieved, or removed at either end of the queue.
LinkedBlockingDeque class provides concurrent queue processing that includes methods:
takeFirst() to retrieve the first element in the queue
takeLast() to retrieve the last element in the queue
These methods will wait until the requested element is available, then retrieves and removes that element.
There is a wealth of information on the web, along with coding examples for implementing Java queues in your applications. Oracle Java Docs is an excellent resource for information on all things Java, including the use of Java queue interfaces.