首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >比较法违反其总合同java7

问比较法违反其总合同java7
EN

Stack Overflow用户
提问于 2015-07-21 17:57:23
回答 1查看 153关注 0票数 1

我知道很多答案都回答了我的问题。在我的代码中,异常说“比较方法违反了它的通用契约”,但是我不知道我的比较方法如何违反它的通用contract.This是我的代码:

代码语言:javascript
复制
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;
}
EN

回答 1

Stack Overflow用户

发布于 2015-08-28 11:37:43

这里有几件微妙的事情。这不是在堆栈溢出的其他地方看到的常见的“比较器损坏”问题。虽然这个比较器确实坏了,但还是很难看出来。

第一个问题是,比较器基本上负责比较Double值,即装箱的double值。>操作符将执行自动拆箱并对包含的值进行数字比较,而==操作符将测试引用相等性。总体而言,

代码语言:javascript
复制
Double.valueOf(1.23) == Double.valueOf(1.23) // WARNING: reference comparison, not numeric!

将是false。如果您真的想测试Double值的数值相等性,那么您必须这样做

代码语言:javascript
复制
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值。

我会像这样重写你的比较器:

代码语言:javascript
复制
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()默认方法,该方法通常会更快:

代码语言:javascript
复制
if (isDesc) {
    res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed());
} else {
    res.sort(Map.Entry.comparingByValue());
}

(不幸的是,类型推断并不能很好地工作,所以你必须提供一个“类型见证”才能得到反向的比较器。)

最后,您可以使用“菱形”运算符和ArrayList复制构造函数来更简洁地复制映射条目。重写的例程如下所示:

代码语言:javascript
复制
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;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31535856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档