我知道很多答案都回答了我的问题。在我的代码中,异常说“比较方法违反了它的通用契约”,但是我不知道我的比较方法如何违反它的通用contract.This是我的代码:
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;
}发布于 2015-08-28 11:37:43
这里有几件微妙的事情。这不是在堆栈溢出的其他地方看到的常见的“比较器损坏”问题。虽然这个比较器确实坏了,但还是很难看出来。
第一个问题是,比较器基本上负责比较Double值,即装箱的double值。>操作符将执行自动拆箱并对包含的值进行数字比较,而==操作符将测试引用相等性。总体而言,
Double.valueOf(1.23) == Double.valueOf(1.23) // WARNING: reference comparison, not numeric!将是false。如果您真的想测试Double值的数值相等性,那么您必须这样做
if (o1.getValue().doubleValue() == o2.getValue.doubleValue()) ...如果您的输入只包含实际的数字值,这将是最有效的。不过,我怀疑您的输入包含NaN值,这些值具有模糊的(甚至是无意义的)行为。特别是,将NaN与任何数值进行比较都是假的,并且NaN与其自身进行比较时并不相等!这违反了所有关于数值比较的排序规则;实际上,NaN对于实数是无序的。这就是排序算法在遇到NaN值时会中断的原因。
(NaN是0.0除以0.0的结果。)
有一个Double.compare(double d1, double d2)方法可以合理地处理NaN;它将NaN值排序在Double.POSITIVE_INFINITY之上。(它还区分了正零和负零,但这不太可能导致您的问题。)有一个配套的方法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);
}
}
}因为Double本身就是Comparable,所以在Java8中,您可以通过在Map.Entry上使用实用程序方法来避免编写自己的比较器。您还可以在List上使用sort()默认方法,该方法通常会更快:
if (isDesc) {
res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed());
} else {
res.sort(Map.Entry.comparingByValue());
}(不幸的是,类型推断并不能很好地工作,所以你必须提供一个“类型见证”才能得到反向的比较器。)
最后,您可以使用“菱形”运算符和ArrayList复制构造函数来更简洁地复制映射条目。重写的例程如下所示:
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;
}https://stackoverflow.com/questions/31535856
复制相似问题