我得到了
“线程中的异常”AWT-EventQueue-0“
java.lang.IllegalArgumentException:比较方法违反了它 总合同!“
此比较器的错误。它用于PriorityQueue
。
public class NodeFPQComp implements Comparator<Node> {
@Override
public int compare(Node arg0, Node arg1) {
int result=0;
if (arg0.getF() - arg1.getF() > 0) result = 1;
if (arg0.getF() - arg1.getF() < 0) result = -1;
return result;
}
}
getF()
是float
值,永远不会接近限制,因此此处不会出现溢出问题。
它只返回另外两个浮点数的总和:
public float getG() {
return this.G;
}
public float getH() {
return this.H;
}
public float getF() {
return getG() + getH();
}
以下是使用它的队列:
openList = new PriorityQueue<Node>((int) gridSizeX()*gridSizeY()/10, new NodeFPQComp());
我想要的是让队列(A-Star路径查找)接受具有相同值(相同的f值)但具有不同身份(地图上的不同节点/方块)的多个对象。
奇怪的是路径查找仍然有效,但为什么我得到例外?那个比较器怎么可能不起作用?我错过了什么?可能是因为在将对象添加到队列之后更改getF()
所依赖的值(这种情况在一个星形中发生了很多)会以某种方式弄乱它吗?
这是完整的堆栈跟踪:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(Unknown Source)
at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(Unknown Source)
at java.awt.FocusTraversalPolicy.getInitialComponent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.SequencedEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
答案 0 :(得分:2)
“合同”表示compare
方法应为总排序。 (编辑)这个 也应该与equals(Object obj)
方法一致(即使它可能没有严格强加),以确保数据结构(如TreeSet,TreeMap)的行为符合您的预期,因为它们可能基于同意和 equals
方法。
确保你有这些。
总排序意味着
a.compareTo(a) >= 0
a
a.compareTo(b) >= 0
和b.compareTo(a) >= 0
表示每a
b
与a,b
“相等”;这意味着a.compareTo(b) == 0
,还有b.compareTo(a) == 0
a.compareTo(b) >= 0
和b.compareTo(c) >= 0
暗示a.compareTo(c) >= 0
,每a,b,c
很容易给出反例,其中compare
方法返回{0,1,-1}且不与总排序一致,因此请特别检查。
答案 1 :(得分:0)
这里有两种可能的失败,这两种失败都可以忽略不计。
第一个可能的失败是arg0或arg1可能为null,在这种情况下,你最终会抛出NullPointerException。这可能是可以接受的,因为很多时候你不会在集合中允许空值。
其他可能的失败是getF()返回某些整数类型(int,byte,long),如果返回值两个getF()调用具有足够大的差异,它们会溢出。
这种比较的最大有效差异取决于类型,对于byte和int,可以是Integer.MAX_VALUE,对于long,可以是Long.MAX_VALUE。
由于您已经在比较减法的结果,为什么不直接比较这两个值?
int result = 0;
if (arg0 != arg1) {
if (arg0 == null) {
result = -1;
} else if (arg1 == null) {
result = 1;
}
if (arg0.getF() < arg1.getF()) {
result = -1;
}
if (arg0.getF() > arg1.getF()) {
result = 1;
}
}
return result;
如果您更喜欢简洁的代码:
return arg0 != null && arg1 != null ?
Integer.compare(arg0.getF(), arg1.getF()) : // Neither are null, compare vlues
arg0 == arg1 ?
0 : // both are null, return 0
arg0 == null ? -1 : 1; // arg0 != arg1, so one of them must be null.