Thursday, 1 June 2017

Java Collections Tutorial 10: The Queue Interface in Java



In this tutorial, we discuss queues in Java. So, what is a queue? A queue is a list of objects. In ordinary day-to-day life, people join a queue at the end, and leave the queue at the front. In Java, and programming in general, the front of the queue is referred to as the “head”, while the end of the queue is referred to as the “tail”. So in Java, we say that we add items to the “tail” of a queue and remove items from the “head” of a queue.


Queues in programming implement the “first-in-first-out” principle, which is just another way of saying that the first item to enter a list is the first one to be removed. Also, the last item to enter a queue is the last item to be removed, as it makes its way from the tail towards the head.


An example of a class that implements the Queue interface is LinkedList. Another example of a class that implements the Queue interface is the ArrayBlockingQueue. There are many classes that implement Queue, but in this tutorial, we are going to look at the ArrayBlockingQueue. Unlike a LinkedList which can have an infinite size, ArrayBlockingQueue has a fixed size. Here is how we can define an ArrayBlockingQueue.


Queue<String> queue1 = new ArrayBlockingQueue<String>(5);


There are two sets of methods that you can use with regards to Queue. The first set of methods throws exceptions while the second set of queue methods returns a special value. 



Throws Exception

Returns Special Value

Insert

add()

offer()

Remove

remove()

poll()

Examine

element()

peek()



The first set of methods throw exceptions if you try to do something that makes no sense. For example, let us try to use the add() method to add more items than the specified size of the queue. We specified that the size of the queue is 5. Let’s try to add six items:


queue1.add(“root”);

queue1.add(“leaves”);

queue1.add(“shoot”);

queue1.add(“fruit”);

queue1.add(“flower”);
queue1.add(“branch”);
 Figure 1: Trying to add more items than the size of an ArrayBlockingQueue


Java will throw an IllegalStateException. You will also notice that when we wrote the above lines, Java didn’t force us to handle the exception. So, this is another example of an unchecked exception, also known as a runtime exception.


We can surround sixth queue1.add(“branch”); with a try-catch block like this:


try {

            queue1.add(“branch”);

} catch (IllegalStateException e) {

            System.out.println(“Can’t add more items to queue.”);
}

Figure 2: Handling an IllegalStateException thrown when you try to add more items than the size of an ArrayBlockingQueue


To see what is inside the queue, we can use a for loop:

for (String content: queue1) {

            System.out.println(content);
}
 Figure 3: To see what is inside a queue


If you want to find out what the head of the queue is, you can use the element() method like this:

System.out.println(“Head of queue is: ” + queue1.element());
 Figure 4: Using the element() method to find out the head of the queue


If you try to call the element() method when there is no item in the queue, Java will throw a NoSuchElementException, which we can surround with a try-catch block like this:


try {

System.out.println(“The head of the queue is: ” + queue1.element());

} catch (NoSuchElementException e) {

            System.out.println(“The queue is empty”);
}
 Figure 5: How to handle the NoSuchElementException thrown when we try to find the head of an empty queue


To remove values from a queue, we use the remove() method. The remove() method will remove the item that is at the head of the queue and return it.


System.out.println(queue1.remove());

System.out.println(queue1.remove());

System.out.println(queue1.remove());

System.out.println(queue1.remove());

System.out.println(queue1.remove());

System.out.println(queue1.remove());

System.out.println(queue1.remove());

If you try to remove more items than there are in a queue, Java will throw a NoSuchElementException, which is also a runtime exception. 
Figure 6: Removing more items than there are in a list leads to the throwing of an exception


So we can also surround the sixth attempt to remove the item from the queue with a try-catch block:


try {

            System.out.println(queue1.remove());

} catch (NoSuchElementException e) {

            System.out.println(“Tried to remove more elements that there are”);

}

Figure 7: How to handle an exception thrown by trying to remove more items than there are in a queue


Queues also have methods that return a special value instead of throwing an exception. Let’s create a new queue for demonstration:


Queue<String> queue2 = new ArrayBlockingQueue<String>(2);


We are going to look at the offer() method, which is similar to the add() method. We will also look at the poll() method, which is similar to the remove() method. Finally, we will look at the peek() method, which is similar to the element() method.


Now, let us add some items to the queue using the offer() method.


queue2.offer(“moss”);

queue2.offer(“algae”);

queue2.offer(“lichen”);


Now, notice that we are trying to add a third item “lichen” despite the fact that we specified that queue2 can only hold two elements. What Java does is it will ignore all the items that are beyond the size of the queue. How do we know this? We can examine the contents of queue2 using a foreach loop like this:


for (String content: queue2) {

            System.out.println(content);
}

Figure 8: Adding items to a queue using the offer() method


Now, let us remove some items to the queue using the poll() method.


queue2.poll();

queue2. poll ();

queue2. poll ();


Now, notice that we are trying to remove a third item “lichen” despite the fact that we specified that queue2 can only hold two elements. What Java does is it will ignore all the items that are beyond the size of the queue. How do we know this? We can examine the contents of queue2 using a foreach loop like this:


for (String content: queue2) {

            System.out.println(content);

}

When we try to remove elements from the queue when there are no elements, Java will return “null”.
Figure 9: Using the poll() method to remove items from a queue


Now, we can use the peek() method to examine the head of the queue like this:

System.out.println(“The head of the queue is: ” + queue2.peek());

Figure 10: Using the peek() method to identify the item at the head of the queue


If there are no items in the queue, the peek() method returns “null”.

So there you go… the Queue interface. It has two sets of methods that do the same things, only that one set of methods throws an exception while the other returns a special value. If you want a bounded list, you can use an ArrayBlockingQueue. But if you want an unbounded queue, use a LinkedList.


Queues are very useful in multithreading and we shall see this in the multithreading section.


In the next tutorial, we are going to look at iterators.


Incase you have any questions or comments, please feel free to leave them in the comments section below and I will address them.

Until next time, take care.  

No comments:

Post a Comment