【问题标题】:Comparison method violates its general contract when sorting比较方法在排序时违反了它的一般约定
【发布时间】:2015-06-17 21:47:28
【问题描述】:

我不断收到:Comparison 方法违反了它的一般合同! 当我调用 Arrays.sort(ScreenItems) 时,以下比较函数的异常
我的一个假设是,下面的 ParseInt 为左侧对象抛出异常,但未向右侧对象抛出异常
是这样吗?

public int compare(Object o1, Object o2) {
    if (o2 == null || o1 == null)
        return 0;

    if (!(o1 instanceof ScreenItem) || !(o2 instanceof ScreenItem))
        return 0;

    ScreenItem item1 = (ScreenItem) o1;
    ScreenItem item2 = (ScreenItem) o2;

    String subSystem1 = item1.getSubSystem();
    String subSystem2 = item2.getSubSystem();

    if(subSystem1.equals(subSystem2)) {
        return 0;
    } else if(subSystem1.startsWith(subSystem2)) {
        return 1;
    } else if (subSystem2.startsWith(subSystem1)) {
        return -1;
    }

    String order1 = item1.getOrder();
    String order2 = item2.getOrder();

    if (order1 == null || order2 == null){
        String name1 = item1.getName();
        String name2 = item2.getName();

        if(name1 == null || name2 == null)
            return 0;

        return name1.compareToIgnoreCase(name2);
    }

    try {
        return Integer.parseInt(order1) - Integer.parseInt(order2);
    } catch (Exception ex) {
        return 0;
    }
}

【问题讨论】:

  • 我建议不要对异常做出假设,而是将日志记录代码放在 catch 块中。无论如何,如果您打算在异常发生后继续计算,您应该更具体地了解您捕获的内容。
  • 要详细说明@PatriciaShanahan 的评论,您可能应该检查两个操作数中的哪一个在解析时引发异常,并针对以下情况制定单独的规则:(1) 无效 op i>有效,(2)有效op无效,(3)无效op无效;所有这些都应该遵循为非数字顺序字符串分配一个固定的排序位置(例如,“非数字顺序在-INT_MAX”之前)。
  • 我认为你应该使用o2 == null || o1 == null
  • @CommuSoft:嗯?这是该方法中的第一件事。 (不过,我完全不确定我是否认为它是正确的。我希望实例不等于 null。)
  • @T.J.Crowder:问题是传递性不再得到保证。因为null == a < b == null的意思是null < null,这违反了顺序关系的传递性。正如here 所说,您应该将null 视为无穷远。

标签: java sorting comparison


【解决方案1】:

这是我认为需要进行的那种改变的一个例子。正如@CommuSoft 在评论中指出的那样,当前对nullo1o2 的处理破坏了传递性。

我会替换:

if (o2 == null || o1 == null)
    return 0;

与:

if (o2 == null && o1 == null)
    return 0;
if (o1 == null)
    return -1;
if (o2 == null)
    return 1;

这将null 视为等于它自己,但小于所有非空引用。当然,您也可以选择将null 视为大于所有非空引用,只要您保持一致即可。如果有任何两个非空引用返回非零值,则将其视为等于所有内容(如在当前代码中所做的那样)是不一致的。

更一般地说,我建议为排序编写一组规则,确保它们符合Comparator 合同,然后编写代码和测试来匹配这些规则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    相关资源
    最近更新 更多