【问题标题】:java exception: Comparison method violates its general contractjava异常:比较方法违反了它的一般约定
【发布时间】:2015-01-15 22:28:51
【问题描述】:

我已经查看过有关此主题的先前帖子 -- thisthis。尽管如此,我还是无法弄清楚下面给出的代码中的合同违规是如何发生的。

public class ScoreComparator 
implements Comparator<Map.Entry<?, Double>> {

public int compare(Map.Entry<?, Double> o1, 
        Map.Entry<?, Double> o2) {
    return o1.getValue().compareTo(o2.getValue());
}   
}

我的使用方式如下:

List<Entry<String, Double>> entryList = 
        new ArrayList<Entry<String, Double>>(
                iterTypeScoreMap.get(keyToSort).entrySet());
Collections.sort(entryList, new ScoreComparator());

iterTypeScoreMap 声明如下

ConcurrentHashMap<String, Map<String, Double>> iterTypeScoreMap;

地图(iterTypeScoreMap)可以在排序过程中发生变化,这就是为什么我制作了一个列表的副本,然后对其调用排序。

由于我使用的是 Double 的内置 compareTo 方法,那不应该处理合同吗?另一个难以调试的原因是这个异常并不总是发生。仅在某些运行期间发生。这里可能是什么错误?

提前致谢。

【问题讨论】:

标签: java comparator compareto


【解决方案1】:

由于输入值(分数)同时更改,您的排序顺序在排序操作期间发生了变化。

当同时修改条目本身时,复制地图的entrySet() 无济于事。您必须对集合进行深度复制,换句话说,也要复制所有 Entry 对象,以防止出现错误。就目前而言,您正在排序的列表引用了与原始地图相同的 Entry 对象。

【讨论】:

  • 是的,我认为这就是问题所在。谢谢你。我根据映射条目创建了 AbstractMap.SimpleImmutableEntry 并将它们插入到要排序的列表中。这似乎已经解决了。
【解决方案2】:

我认为问题在于a.compareTo(b)==0 应该隐含a.equals(b)

但是,如果您的键不同但值相同,则两者将具有 a.compareTo(b)==0a.equals(b) 将是 false

【讨论】:

  • 不,这不是暗示。只是强烈建议。
  • 我认为 OP 使用的任何排序算法都可能假设(尽管不正确)它是隐含的。我知道TreeSet 会删除不相等但a.compare(b)==0 所在的元素。
  • 来自TreeMap 文档:有序映射的行为是明确定义的,即使它的排序与equals不一致;它只是不遵守 Map 接口的一般约定。
猜你喜欢
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多