3

我的一个应用程序曾经抛出一个 IllegalArgumentException ,指出比较方法违反了它的一般合同。我找到了一些详细说明问题的来源,例如http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6804124http://www.oracle.com/technetwork/java/javase/compatibility-417013。 html#source并想在我的应用程序中解决这个问题。

但我无法重现该问题,因此无法知道我的修复是否正确。

在我努力重现的过程中,我试图尽可能地简化问题,并提出了一个如下所示的小类:

public class Sortee implements Comparable<Sortee>
{
  /** a value to sort by */
  public final int _x;

  public Sortee(int x)
  {
    _x = x;
  }

  public int compareTo(Sortee o)
  {
    return 1;
  }
}

我还创建了一个等价的比较器:

public class SorteeIncorrectComparator implements Comparator<Sortee>
{
  public int compare(Sortee a, Sortee b)
  {
    return 1;
  }
}

在另一个类中,我创建了一个 Sortee 对象列表并调用 Collections.sort() 变体来引发 IllegalStateException:

private static void sort()
{
   List<Sortee> sortees = createSortees();

   Collections.shuffle( sortees );
   Collections.sort( sortees, new SorteeIncorrectComparator() );

   Collections.shuffle( sortees );
   Collections.sort( sortees );
}

但是永远不会引发 IllegalStateException。

我已经在 Linux 和 Windows 上以及在 Windows 上使用 Java 1.7.0_21、23.21-b01 的 Eclipse 中进行了尝试,并检查了属性 java.util.Arrays.useLegacyMergeSort 是否未设置。

我认为在 compare 方法中总是返回 1 应该会破坏契约,因为它既不是可交换的也不是传递的。

为什么我永远不会收到 IllegalStateException?

4

3 回答 3

2
public static void main(String[] args) {
    Object[] array = new Object[37];
    for (int i = 0; i < array.length; i++) {
        array[i] = new Object();
    }
    Arrays.sort(array, new Comparator<Object>() {
        private int result[] = {1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 0, -1, -1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
        private int index;
        @Override
        public int compare(Object o1, Object o2) {
            return result[index++];
        }
    });
}
于 2013-09-27T19:37:42.080 回答
1

当比较器违反 a=b 和 b=c -> a=c 时,我能够重现这一点,然后 timsort 似乎在抱怨。我的测试是:

List<Integer> timSortTestList = new ArrayList<Integer>();
{
    for(int i=0; i<100; ++i) {
        timSortTestList.add(i);
        timSortTestList.add(i);
        timSortTestList.add(i);
    }
    Collections.shuffle(timSortTestList, new Random(42));
}
Comparator<Integer> broken = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        if (Math.abs(o1-o2) < 10) {
            return Compare.EQUAL; // WRONG
        }
        return Ordering.natural().compare(o1, o2);
    }
};
Collections.sort(timSortTestList, broken); // throws up

比较这个问题- 发生这种情况时也许有一个一般规则。

于 2014-07-25T08:28:13.660 回答
0

我的实现实际上是可传递的。

我更改了比较方法以返回随机值,这引发了异常。

于 2013-06-10T09:19:10.403 回答