为什么我的比较方法会引发异常 -- 比较方法违反了其总协定!

2022-09-03 16:28:20

为什么此代码

public class SponsoredComparator implements Comparator<SRE> {

    public boolean equals(SRE arg0, SRE arg1){
        return arg0.getSponsored()==arg1.getSponsored();
    }

    public int compare(SRE object1, SRE object2) {
        Log.d("SponsoredComparator","object1.getName() == "+ object1.getName());
        Log.d("SponsoredComparator","object1.getSponsored() == "+ object1.getSponsored());
        Log.d("SponsoredComparator","object2.getName() == "+ object2.getName());
        Log.d("SponsoredComparator","object2.getSponsored() == "+ object2.getSponsored());
        Log.d("SponsoredComparator","compare return == "+ (object1.getSponsored() && object2.getSponsored() ? 0 : object1.getSponsored() ? -1 : 1));
        return object1.getSponsored() && object2.getSponsored() ? 0 : object1.getSponsored() ? -1 : 1;
    }
}

引发此异常:ERROR/AndroidRuntime(244): java.lang.IllegalArgumentException: Comparison method violates its general contract!
ERROR/AndroidRuntime(4446): at java.util.TimSort.mergeLo(TimSort.java:743)

方法 sre.getSponsored() 返回一个布尔值。

谢谢。


答案 1

我怀疑当两个值都没有被赞助时,问题就会发生。无论您以何种方式称呼它,都将返回1,即

x1.compare(x2) == 1

x2.compare(x1) == 1

这是无效的。

我建议你改变这个:

object1.getSponsored() && object2.getSponsored()

object1.getSponsored() == object2.getSponsored()

在这两个地方。我可能实际上会在某个地方提取出一个带有此签名的方法:

public static int compare(boolean x, boolean y)

然后这样称呼它:

public int compare(SRE object1, SRE object2) {
    return BooleanHelper.compare(object1.getSponsored(), object2.getSponsored());
}

这将使代码更清晰,IMO。


答案 2

我假设您使用的是 JDK 7。请检查以下网址:

http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#source

领域: API: 实用程序

概要:更新了 的排序行为,并可能引发ArraysCollectionsIllegalArgumentException

说明:和 (间接)使用的排序算法已被替换。新的排序实现可能会抛出一个 if,如果它检测到违反协定的 。之前的实现默默地忽略了这种情况。如果需要以前的行为,则可以使用新的系统属性 来还原以前的合并排序行为。java.util.Arrays.sortjava.util.Collections.sortIllegalArgumentExceptionComparableComparablejava.util.Arrays.useLegacyMergeSort

不相容性的性质:行为

RFE: 6804124

有关更多详细信息,请参阅此处的 Bug 数据库参考


推荐