ArrayList.sort() 方法中的 IllegalArgumentException
IllegalArgumentException in ArrayList.sort()-method
我遇到了以下异常,我不太明白为什么:
java.lang.IllegalArgumentException: Comparison method violates its
general contract!
at java.util.TimSort.mergeLo(TimSort.java:777) at
java.util.TimSort.mergeAt(TimSort.java:514) at
java.util.TimSort.mergeCollapse(TimSort.java:441) at
java.util.TimSort.sort(TimSort.java:245) at
java.util.Arrays.sort(Arrays.java:1512) at
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,它突然毫无例外地工作。
但为什么?这应该只会改变排序顺序,不会破坏整个比较器。
我错过了什么?
你的比较器违反了约定,因为当两个参数都是 false
时,它将 return 1
由于声明 if (!lineItem1) { return 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());
我遇到了以下异常,我不太明白为什么:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:777) at java.util.TimSort.mergeAt(TimSort.java:514) at java.util.TimSort.mergeCollapse(TimSort.java:441) at java.util.TimSort.sort(TimSort.java:245) at java.util.Arrays.sort(Arrays.java:1512) at 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,它突然毫无例外地工作。 但为什么?这应该只会改变排序顺序,不会破坏整个比较器。
我错过了什么?
你的比较器违反了约定,因为当两个参数都是 false
时,它将 return 1
由于声明 if (!lineItem1) { return 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());