代码之家  ›  专栏  ›  技术社区  ›  CoXier

比较法违反其总合同![副本]

  •  -2
  • CoXier  · 技术社区  · 7 年前

    我在谷歌上搜索了一些相同的问题,我知道原因。然而,坠机事件只发生过一次,所以我来这里是想问你什么可能导致坠机。

        Collections.sort(downloadTasks, new Comparator<DownloadTask>() {
            @Override
            public int compare(DownloadTask lhs, DownloadTask rhs) {
                if (lhs == null || rhs == null) return 0;
                return (int) (lhs.mTaskInfo.time - rhs.mTaskInfo.time);
            }
        });
    

    错误是:

    Java语言lang.IllegalArgumentException:比较法违反其总合同!在java。util。蒂姆索特。mergeHi(TimSort.java:864) 在java。util。蒂姆索特。mergeAt(TimSort.java:481) 在java。util。蒂姆索特。mergeCollapse(TimSort.java:406) 在java。util。蒂姆索特。排序(TimSort.java:210) 在java。util。阵列。排序(数组。java:2010) 在java。util。收藏。排序(Collections.java:1883)

    如你们所见,我通过它们的 time 成员这个 long 类型

    我认为坠机原因可能是:

    • 将long转换为int是否会导致崩溃?
    • 但理论上lhs和rhs都不为空。

    如果 lhs rhs

    为Android编辑

    Long.compare() 需要API 19。您可以在API 19下执行此操作:

    public static int compare(long lhs, long rhs) {
        return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1);
    }
    
    2 回复  |  直到 7 年前
        1
  •  5
  •   Thilo    7 年前

    这两种情况都有问题。

    if (lhs == null || rhs == null) return 0;

    如果你有 [123, null, 234] ,然后比较 123 null , 无效的 等于 234 123 234

    这里的解决方案是要么不允许 nulls 到底部(或顶部),即仅返回 0 二者都 1 -1 (取决于 无效的 向左或向右)。

    return(int)(lhs.mTaskInfo.time-rhs.mTaskInfo.time);

    考虑比较 Integer.MAX_VALUE + 1 . 将此转换为 int 换行到 Integer.MIN_VALUE . 相反的比较应该给你 - Integer.MIN_VALUE 但是 that is Integer.MIN_VALUE again due to overflow

    这里的解决方案是使用 Long.compare(a,b)

        2
  •  2
  •   Community T.Woody    4 年前

    compare(T o1, T o2) 方法:

    实施者必须确保 sgn(compare(x, y)) == -sgn(compare(y, x)) x y . (这意味着 compare(x, y) 必须抛出异常当且仅当 compare(y, x)

    实施者还必须确保关系是可传递的: ((compare(x, y)>0) && (compare(y, z)>0)) compare(x, z)>0 .

    最后,实施者必须确保 compare(x, y)==0 意味着 sgn(compare(x, z))==sgn(compare(y, z)) 对于所有z。

    那么,你违反了这三条规则中的哪一条? 全部3个

    违反第一条规则是因为 time long 所以 (int) (lhs.mTaskInfo.time - rhs.mTaskInfo.time) 可以等于 Integer.MIN_VALUE . 如果将这两个参数翻转为 compare() 整数最小值 ,因为 int

    违反第二条规则是因为 整数 时间 长的 ,我假设它们包含标准毫秒值,并且 24天 . 假设输入是 Jan 1, Jan 15, Jan 30 . compare(Jan 1, Jan 15) compare(Jan 15, Jan 30) compare(Jan 1, Jan 30) 应该是+29天,但溢出的返回时间大约是-19天。哎呀!!!!

    null, Jan 1, Jan 2 . compare(null, Jan 1) compare(null, Jan 2) 但是 compare(Jan 1, Jan 2) 是+1天。

    解决方案

    这个 溢流和 MIN_VALUE 问题可以通过使用 Long.compare(long x, long y) .

    对于 null

    public int compare(DownloadTask lhs, DownloadTask rhs) {
        if (lhs == null) {
            if (rhs == null)
                return 0;
            return -1;
        }
        if (rhs == null)
            return 1;
        return Long.compare(lhs.mTaskInfo.time, rhs.mTaskInfo.time);
    }
    

    public int compare(DownloadTask lhs, DownloadTask rhs) {
        return (lhs == null ? (rhs == null ? 0 : -1)
                : (rhs == null ? 1 : Long.compare(lhs.mTaskInfo.time, rhs.mTaskInfo.time)));
    }