添加不可比较的对象时,PriorityQueue的大小会增加

时间:2015-08-31 21:02:05

标签: java priority-queue

请考虑以下代码:

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

在此代码中,首先将不可比较的对象添加到PriorityQueue。此代码工作正常,as already answered here

然后,第二个对象被添加到此队列中。按照PriorityQueue.add Javadoc的预期,抛出ClassCastException,因为第二个对象与第一个对象不可比。

但是,虽然引发了异常,但似乎队列的大小增加了:第二个print语句输出2而不是1。

预计会出现这种情况吗?如果是这样,背后的原因是什么?它在哪里记录?

2 个答案:

答案 0 :(得分:9)

根据GrepCode.com的version of the source,看起来它可能是实施中的一个错误。

所有添加功能都是调用

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

offer功能如下所示

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;
}

你会注意到在通过siftUp实际插入项目之前调用了size = i + 1。当调用siftUp时,它首先要做的是尝试强制转换为Comparable并在实际插入项之前抛出异常。因此,它会增加大小而不实际插入项目。

答案 1 :(得分:2)

offer的源代码(由add调用)显示将非Comparable对象传递给PriorityQueue时未发生的无效状态。有一个Comparator

public boolean More 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;
}

在调用siftUp之前修改大小。通常负责将元素插入队列的siftUp方法(最终)会抛出ClassCastException,但是大小已经被修改,大小不正确。

即使发生size,似乎也没有记录ClassCastException会增加。一个简单的解决方法是将行size = i + 1;放在if / else之后和return语句之前。