Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Size of PriorityQueue increases when non-comparable objects are added

Consider the following code:

import java.util.PriorityQueue;

public class Test {

    public static void main(String argv[]) {
        PriorityQueue<A> queue = new PriorityQueue<>();
        System.out.println("Size of queue is " + queue.size()); // prints 0
        queue.add(new A()); // does not throw an exception
        try {
            queue.add(new A()); // this time, an exception is thrown
        } catch (ClassCastException ignored) {
            System.out.println("An exception was thrown");
        }
        System.out.println("Size of queue is " + queue.size()); // prints 2
    }

} 

class A { } // non-comparable object

In this code, a non-comparable object is first added to a PriorityQueue. This code works fine, as already answered here.

Then, a second object is added to this queue. As expected per PriorityQueue.add Javadoc, a ClassCastException is thrown because the second object is not comparable to the first one.

However, it seems that the size of the queue was increased although an exception was thrown: the second print statement outputs 2 instead of 1.

Is this behaviour expected? If so, what is the reason behind this and where is it documented?

like image 617
Tunaki Avatar asked Aug 31 '15 21:08

Tunaki


1 Answers

According to GrepCode.com's version of the source, it looks like it may be a bug in their implementation.

All the add function does is call

public boolean add(E e) {
    return offer(e);
}

The offer function looks like this

public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
    modCount++;
    int i = size;
    if (i >= queue.length)
        grow(i + 1);
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);
    return true;
}

You'll notice that size = i + 1 is called before the item is actually inserted via siftUp. When siftUp is called, the very first thing that it does is try to cast to Comparable and throws the exception before actually inserting the item. Therefore it increments the size without actually inserting an item.

like image 107
spectacularbob Avatar answered Nov 11 '22 07:11

spectacularbob