java - 将 useLegacyMergesort 实现为 true 后,Collection.sort 在 JDK 8 中无法正确排序

标签 java mergesort

我正在将一个项目从 JDK 7 升级到 JDK 8,最初我们遇到了一个异常:

java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.mergeHi(Unknown Source) at java.util.TimSort.mergeAt(Unknown Source) at java.util.TimSort.mergeCollapse(Unknown Source) at java.util.TimSort.sort(Unknown Source) at java.util.Arrays.sort(Unknown Source) at java.util.ArrayList.sort(Unknown Source) at java.util.Collections.sort(Unknown Source)

我们通过使用java.util.Arrays.useLegacyMergeSort的系统属性作为true来解决这个问题。之后异常得到解决,但它执行的排序是错误的(排序不正确)。

注意:在 JDK 7 中,相同的代码可以完美运行(没有此系统属性)

public class SortTableModelRowComparator implements Comparator<TableModelSortingRow>
{   
    private boolean   ascending = true;
    protected int[]   sortingColumns;

    /**
     * Constructor
     * 
     */
    public SortTableModelRowComparator(boolean pSortAscendending, int[] pSortingColumns)
    {
        ascending=pSortAscendending;
        sortingColumns=pSortingColumns;
    }

    @Override
    public int compare(TableModelSortingRow o1,
            TableModelSortingRow o2) {
        BigDecimal firstvalue=(BigDecimal)o1.getValue(7);
        BigDecimal secondvalue=(BigDecimal)o2.getValue(7);

        return firstvalue.compareTo(secondvalue);
    }
}

最佳答案

这就是使用该标志的问题。

原来的异常是指你的Comparator有问题或Comparable的比较运算。它的某些内容违反了 Comparable有效比较需要遵守的契约1。本质上,这是您的应用程序中的一个错误。

当您设置该标志时,您就是在告诉 JVM 忽略该问题。在某些情况下,您可以逃脱惩罚。在其他情况下......比如你的......后果将是不正确的。

解决方案:找出出现异常的原因,并解决该问题。

请注意,这可能是比较本身的问题,也可能是在对对象进行排序时发生了某些变化,这就是导致违反契约(Contract)的原因。

<小时/>

Note: In JDK 7 same code work perfectly(without this System properties)

Java 7 和 Java 8 中使用的排序算法不同2。但是,您很可能在 Java 7 中得到了不正确的排序,而您却没有注意到。

<小时/>

1 - Comparator contract如下:

“在前面的描述中,符号sgn(expression)表示数学符号函数,它被定义为根据表达式的值是负数、零还是正数返回-1、0或1之一.

  • 实现者必须确保 sgn(compare(x, y)) == -sgn(compare(y, x))对于所有人xy 。 (这意味着 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

2 - 此外,在 Java 7 中,算法的实现不会检查比较操作中的不正确行为。这解释了为什么在 Java 7 中没有异常(exception)。

关于java - 将 useLegacyMergesort 实现为 true 后,Collection.sort 在 JDK 8 中无法正确排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37805639/

相关文章:

java - 启动 MS Outlook,并在电子邮件中添加附件

java - BindingResult 和 bean 名称的普通目标对象都不能作为请求属性

Java 9 Flow 使用 lambda 定义订阅者

java - 合并排序中的子数组大小

c - merge_sort 不起作用,输出只是一堆 1 -1 和 0

java - 删除除 jsoup 中 h1 标签之后第一个 div 之外的所有 div 元素

java - 未找到 Retrofit 注释。 (参数#2)

java - 合并不等长的排序数组

c++ - 多次拆分链表导致堆栈溢出 C++

java - 在函数内更改 Java 中的对象