Android - 比较方法违反了其总合同

Dis*_*Dev 3 java collections mergesort android

我已经看到了有关此异常的其他问题,但我的比较方法非常简单,我无法弄清楚它有什么问题,我无法使用我拥有的任何Android设备重现它.

我从我的Android应用程序的一些用户那里得到了这个例外,其中大多数似乎是在GS3或GS4这样的新设备上,我猜测它运行Java 7变种的合并排序.

这是我的比较方法:

            Collections.sort(collectionOfThings, new Comparator<Thing>()
            {
                public int compare(Thing lhs, Thing rhs) 
                {
                    //getDist() returns a Double with a capital D...perhaps that has something to do with it?
                    if(lhs.getDist() < rhs.getDist())
                    {
                        return -1;
                    }
                    if(lhs.getDist() == rhs.getDist())
                    {
                        return 0;
                    }

                    return 1;
                };
            });
Run Code Online (Sandbox Code Playgroud)

这是例外:

Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(TimSort.java:743)
    at java.util.TimSort.mergeAt(TimSort.java:479)
    at java.util.TimSort.mergeCollapse(TimSort.java:404)
    at java.util.TimSort.sort(TimSort.java:210)
    at java.util.TimSort.sort(TimSort.java:169)
    at java.util.Arrays.sort(Arrays.java:2038)
    at java.util.Collections.sort(Collections.java:1891)
Run Code Online (Sandbox Code Playgroud)

似乎仅限于Android 4.0+.任何帮助是极大的赞赏.

NIN*_*OOP 9

没有用于重新发明轮子.我相信你应该返回lhs.getDist().compareTo(rhs.getDist());并让提供实施的CompareTo做的工作.

以数字方式比较两个Double对象.

当应用于原始double值时,此方法执行的比较有两种方式与Java语言数值比较运算符(<,<=,==,> =,>)执行的比较不同:

  1. Double.NaN被此方法视为等于其自身并且大于所有其他double值(包括Double.POSITIVE_INFINITY).

  2. 该方法认为0.0d大于-0.0d.

这确保了此方法强加的Double对象的自然顺序与equals一致.

我相信你得到这个例外,因为你现在的实施可能不容易处理Double.NaNpositive/negative zero价值观,但仍然遵守一般合同.看看OpenJDK Double#compare(double,double)源代码:

public static int More ...compare(double d1, double d2) {
   if (d1 < d2)
        return -1;           // Neither val is NaN, thisVal is smaller
    if (d1 > d2)
        return 1;            // Neither val is NaN, thisVal is larger

    long thisBits = Double.doubleToLongBits(d1);
    long anotherBits = Double.doubleToLongBits(d2);

    return (thisBits == anotherBits ?  0 : // Values are equal
            (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
             1));                          // (0.0, -0.0) or (NaN, !NaN)
}
Run Code Online (Sandbox Code Playgroud)

还要查看Double#equals()的文档

请注意,在大多数情况下,对于Double,d1和d2类的两个实例,当且仅当d1.doubleValue()== d2.doubleValue()时,d1.equals(d2)的值为true

也有值true.但是,有两个例外:

如果d1和d2都表示Double.NaN,则equals方法返回true,即使Double.NaN == Double.NaN的值为false.如果d1表示+0.0而d2表示-0.0,反之亦然,则等值测试的值为false,即使+0.0 == - 0.0的值为true.