获取错误:比较方法违反了其一般合同

时间:2016-08-17 20:14:27

标签: java collections java-7 comparator

我在网上尝试了许多可能的解决方案,比如设置System属性并转换为double但仍然得到相同的错误:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:835)
    at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:453)
    at java.util.ComparableTimSort.mergeForceCollapse(ComparableTimSort.java:392)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:191)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
    at java.util.Arrays.sort(Arrays.java:472)
    at java.util.Collections.sort(Collections.java:155)

这是我的代码:

        System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
        Collections.sort(docs, new Comparator<FeedDocument>() {
            public int compare(FeedDocument o1, FeedDocument o2) {

                int year1 = 0;
                int year2 = 0;
                int returnResult = 0;
                if (o1.containsKey(FeedConstants.PUBLICATION_YEAR)
                        && o2.containsKey(FeedConstants.PUBLICATION_YEAR)
                        && o1.get(FeedConstants.PUBLICATION_YEAR) != null
                        && (o1.get(FeedConstants.PUBLICATION_YEAR) instanceof String)
                        && o2.get(FeedConstants.PUBLICATION_YEAR) != null
                        && (o2.get(FeedConstants.PUBLICATION_YEAR) instanceof String)) {

                    String firstyear = (String) o1.get((FeedConstants.PUBLICATION_YEAR));
                    String secondyear = (String) o2.get((FeedConstants.PUBLICATION_YEAR));

                    if (firstyear.equals(secondyear)) {
                        return 0;
                    } else if (firstyear != null && !firstyear.isEmpty() && secondyear != null
                            && !secondyear.isEmpty()) {

                        year1 = Integer.parseInt(firstyear.trim());

                        year2 = Integer.parseInt(secondyear.trim());

                        // int result = year2 - year1;
                        // if (result > 0) {
                        // returnResult = 1;
                        // } else if (result < 0) {
                        // returnResult = -1;
                        // }
                        return Double.compare(year2, year1);
                    }

                } else {
                    returnResult = 0;
                }
                return returnResult;
            }
        });

2 个答案:

答案 0 :(得分:4)

很确定我知道这里发生了什么......

补充:

o1.get(FeedConstants.PUBLICATION_YEAR) != null
o2.get(FeedConstants.PUBLICATION_YEAR) == null
o3.get(FeedConstants.PUBLICATION_YEAR) != null

然后:

compare (o1, o2); //returns 0
compare (o2, o3); //returns 0
compare (o1, o3); //returns not 0

因此,您声明o1 == o2 == o3o1 != o3

答案 1 :(得分:0)

Edward Peters' answer在诊断问题时是正确的,因为compare方法不会产生一致(传递)结果。

解决此问题的最佳方法类似于compare方法中的以下内容:

if (o1.get(FeedConstants.PUBLICATION_YEAR) instanceof String) {
    if (o2.get(FeedConstants.PUBLICATION_YEAR) instanceof String) {
        // Perform the comparison here like you are
    } else {
        /*
         * This could also be 1, the key is to have it consistent
         * so the final sorted list clearly separates the FeedDocuments
         * with a String PUBLICATION_YEAR and those without one.
         */
        return -1;
    }
} else if (o2.get(FeedConstants.PUBLICATION_YEAR) instanceof String) {
    /*
     * In this case, o1 doesn't have a String PUBLICATION_YEAR and o2
     * does, so this needs to be the opposite of the return value
     * 6 lines up to be consistent.
     */
     return 1;
} else {
     /*
      * Consider all FeedDocuments without a String PUBLICATION_YEAR
      * to be equivalent, otherwise you could do some other comparison
      * on them here if you wanted.
      */
     return 0;
}

关键是,如果您只关心正在排序的列表的子集(FeedDocument的{​​{1}}出版年份,那么您需要先将它们与列表的其余部分分开您不关心被排序(当String中的一个有FeedDocument出版年份而另一个没有时,返回1或-1。然后,您可以自由地对所需的子集进行排序,但结果不一致。