【问题标题】:IllegalArgumentException in ArrayList.sort()-method [duplicate]ArrayList.sort() 方法中的 IllegalArgumentException [重复]
【发布时间】:2018-07-01 07:28:36
【问题描述】:

我遇到了以下异常,但我不太明白为什么:

java.lang.IllegalArgumentException:比较方法违反了它的 总承包!

在 java.util.TimSort.mergeLo(TimSort.java:777) 在 java.util.TimSort.mergeAt(TimSort.java:514) 在 java.util.TimSort.mergeCollapse(TimSort.java:441) 在 java.util.TimSort.sort(TimSort.java:245) 在 java.util.Arrays.sort(Arrays.java:1512) 在 java.util.ArrayList.sort(ArrayList.java:1454)

我编写了以下 JUnit 测试来验证行为:

@Test
public void testComparator() {
    List<Boolean> item = new ArrayList<>();

    item.add(true);
    for (int i = 0; i < 1000000; i++) {
        item.add(false);
    }

    while(true) {
        System.out.println("Sorting");
        Collections.shuffle(item);

        item.sort((lineItem1, lineItem2) -> {
            if (lineItem1 && lineItem2) {
                return 0;
            } else if (!lineItem1) {
                return 1; 
            } else if (!lineItem2 ) {
                return -1;
            } 

            return 0;
        });
    }
}

如果我交换 return 1 和 return -1,它会毫无例外地突然工作。 但为什么?这应该只改变排序顺序而不破坏整个比较器。

我错过了什么?

【问题讨论】:

  • 已经检查this
  • 您违反了合同,因为您当前在 lineItem1 为 false 时返回 1,无论 lineItem2 具有什么值。但如果两者都是 false,则需要返回 0。
  • 你试过比较(假,假)吗?
  • @C.Koenig compare(A=false, B=false) 返回 1 但 compare(B=false, A=false) 也返回 1。那么在这种情况下,哪个排序更高:甲还是乙?毕竟两者都比另一个大。
  • 如果可以允许我就这个主题发表我的演讲...... 第 1 部分:youtu.be/Enwbh6wpnYs ... 第 2 部分:youtu.be/bvnmbRo7a1Y

标签: java java-8 comparator


【解决方案1】:

你的比较器违反了约定,因为当两个参数都是false时,由于if (!lineItem1) { return 1; }…的声明,它将返回1

通常,不能保证 TimSort 会发现不正确的比较器,它不会主动尝试查找违反合同的情况,它只是将某些情况检测为算法的副作用。

你真正想要的是

item.sort((lineItem1, lineItem2) -> {
    if (lineItem1.equals(lineItem2)) {
        return 0;
    } else if (!lineItem1) {
        return 1; 
    } else {
        return -1;
    }
});

虽然你可以达到同样的效果

item.sort((lineItem1, lineItem2) -> lineItem1^lineItem2? lineItem1? -1: 1: 0);

甚至更简单

item.sort(Comparator.reverseOrder());

【讨论】:

  • 所以它基本上是运气,当我交换订单时没有抛出异常?
  • @C.Koenig 完全正确。在引入 TimSort 算法之前,从来没有报告过这样的问题,你甚至可以有幸看到想要的结果顺序,或者更确切地说,运气不好,因为你没有注意到代码中仍然存在的问题......
猜你喜欢
  • 2019-03-07
  • 2012-07-08
  • 2018-04-23
  • 2011-08-07
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多