我知道很多答案已经回答了我的问题。在我的代码中,异常说“比较方法违反了它的一般合同”,但我不知道我的比较方法如何违反了它的一般合同。这是我的代码:
public static List<Entry<Integer, Double>> sortMap(
Map<Integer, Double> curMap, final boolean isDesc) {
List<Entry<Integer, Double>> res = new ArrayList<Entry<Integer, Double>>();
for (Entry<Integer, Double> iter : curMap.entrySet()) {
res.add(iter);
}
Collections.sort(res, new Comparator<Entry<Integer, Double>>() {
public int compare(Entry<Integer, Double> o1,
Entry<Integer, Double> o2) {
if (o1.getValue() == o2.getValue()) {
return 0;
} else if (o1.getValue() > o2.getValue()) {
return isDesc ? -1 : 1;
}
return isDesc ? 1 : -1;
}
});
return res;
}
这里发生了一些微妙的事情。这不是堆栈溢出中其他地方常见的“比较器损坏”问题。虽然这个比较器确实坏了,但很难看到。
第一个问题是比较器基本上负责比较双精度
值,即盒装双精度
值。而
Double.valueOf(1.23) == Double.valueOf(1.23) // WARNING: reference comparison, not numeric!
将是
假
的。如果你真的想测试双精度
值的数字相等性,你必须这样做
if (o1.getValue().doubleValue() == o2.getValue.doubleValue()) ...
如果您的输入只包含实际的数值,这种方法通常会有效。不过,我怀疑您的输入包含< code>NaN
值,这些值具有模糊(甚至无意义)的行为。特别是将< code>NaN与任何数值比较都是假的,< code>NaN比较不等于自身!这违反了所有关于数字比较的排序规则;事实上,< code>NaN相对于实数是无序的。这就是为什么排序算法在遇到< code>NaN值时会中断。
(NaN
是0.0除以0.0的结果。)
有一个方法<code>Double。比较(双d1,双d2),合理处理NaN
;它将<code>NaN</code>值排序在<code>Double.POSITIVE_INFINITY</code>之上。(它还区分了正零和负零,但这不太可能导致您的问题。)有一个伴生方法<code>Double。compareTo(Double),用于比较装箱Double
值。
我会像这样重写你的比较器:
Collections.sort(res, new Comparator<Entry<Integer, Double>>() {
public int compare(Entry<Integer, Double> o1,
Entry<Integer, Double> o2) {
if (isDesc) {
return o2.getValue().compareTo(o1);
} else {
return o1.getValue().compareTo(o2);
}
}
}
由于<code>Double</code>本身就是<code>Comparable</code>,所以在Java8中,您可以通过在<code>Map.Entry</code>上使用实用程序方法来避免编写自己的比较器。您还可以在List
上使用sort()
default方法,这通常会更快:
if (isDesc) {
res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed());
} else {
res.sort(Map.Entry.comparingByValue());
}
(不幸的是,类型推断不太起作用,因此您必须提供“类型见证”才能获得反向比较器。)
最后,您可以使用“diamond”操作符和ArrayList
copy构造函数更简洁地复制映射条目。重写后的例程如下所示:
public static List<Entry<Integer, Double>> sortMap(
Map<Integer, Double> curMap, final boolean isDesc) {
List<Entry<Integer, Double>> res = new ArrayList<>(curMap.entrySet());
if (isDesc) {
res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed());
} else {
res.sort(Map.Entry.comparingByValue());
}
return res;
}
我正在根据下面的比较器对集合进行排序。 这些值总是非空的。getOrderSendTime()对象属于java.util.Date类。 我知道这是一种传递性不一致,我认为这样的类不会有这样的问题。我搜索了未解决的问题,但没有找到有关该主题的任何问题。 有什么想法吗?
我已经在类上实现了Comaprable,它给了我比较方法违反了它的总合同!,由于有一些值返回为 null,代码如下 公共静态比较器名称比较器 = 新比较器() {
我试图使用比较器基于两个字符串的比较对数组列表进行排序,但我最终使用的比较方法违反了它的一般契约错误。如果字符串中出现空值比较,我该如何处理? 密码 错误
我看到我的应用程序在一些中国 Android 手机上发生了很多崩溃,并出现错误:比较方法违反了其总合同! 我读过这与Collections.sort有关。 我不太确定的是,这是否是因为我的自定义比较器。 以下是错误发生的地方: 比较器是这样的: 所以我不太确定比较器是否搞砸了什么,或者我是否需要以不同的方式进行collections.sort调用 感谢任何帮助
我收到以下错误:“比较方法违反了它的一般合同!”当使用下面的比较器时,我无法使用jUnit复制异常。我想知道是什么导致了这个问题,以及如何复制它。有其他人也有同样的问题,但不知道如何复制。 使用以下方法调用该代码: 感谢任何帮助。 额外信息:该错误似乎发生在Java utils中的TimSort类中,并来自一个名为mergeLo的方法。链接:http://grepcode.com/file/rep
我有一个自己的,相对复杂的字符串比较器和一个庞大的字符串列表(~100个字符串,已经尝试减少,但问题不可重现),其中对它们进行排序会产生上述错误尝试使用Java 7排序。我想,规则 可能会被侵犯。找出违反合同的样品的最好方法是什么?