当前位置: 首页 > 知识库问答 >
问题:

比较法违反了其通用合同java7

微生毅然
2023-03-14

我知道很多答案已经回答了我的问题。在我的代码中,异常说“比较方法违反了它的一般合同”,但我不知道我的比较方法如何违反了它的一般合同。这是我的代码:

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

共有1个答案

羊禄
2023-03-14

这里发生了一些微妙的事情。这不是堆栈溢出中其他地方常见的“比较器损坏”问题。虽然这个比较器确实坏了,但很难看到。

第一个问题是比较器基本上负责比较双精度值,即盒装双精度值。而

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”操作符和ArrayListcopy构造函数更简洁地复制映射条目。重写后的例程如下所示:

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排序。我想,规则 可能会被侵犯。找出违反合同的样品的最好方法是什么?