请考虑以下代码:
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。
预计会出现这种情况吗?如果是这样,背后的原因是什么?它在哪里记录?
答案 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语句之前。