英文:
An error "Comparison method violates its general contract" when compare Date via before()
问题
我已经使用了 list.sort()
来对一个包含类型为 Date
的对象的列表进行排序,但是得到了 java.lang.IllegalArgumentException: Comparison method violates its general contract! 这个错误让我感到非常困惑。
以下是代码示例:
List<Date> list = new ArrayList<>(200);
Date now = new Date();
for (int i = 0; i < 200; ++i) {
int delta = ThreadLocalRandom.current().nextInt(2, 10);
list.add(DateUtils.addMinutes(now, delta));
}
list.sort((x, y) -> {
int cmp = x.before(y) ? -1 : 1;
return cmp;
});
我在谷歌上搜索了一下,发现了很多类似的问题(https://stackoverflow.com/questions/11441666/java-error-comparison-method-violates-its-general-contract),都说这个比较器不满足传递性规则。然而,似乎 Date.before
应该是遵循传递性规则的。
我知道这个比较器在比较两个相同日期时会有问题。对于任意两个相同的日期,比如 d1
、d2
,cmp(d1, d2)
和 cmp(d2, d1)
都会返回 1。
然而,如果我们将比较器替换为始终返回 1,就不会抛出错误。
list.sort((x, y) -> 1);
在上面的示例中,我创建了很多重复的日期,用来复现这个错误。尽管我知道如何解决这个问题,但我仍然想知道为什么使用 before()
会失败。
顺便说一下,我在 JDK 8 和 11 上都进行了测试,都失败了。
英文:
I have used list.sort()
to sort a list of objects with type Date
, and got java.lang.IllegalArgumentException: Comparison method violates its general contract! I feel quite confusing about this error.
The code as below shown
List<Date> list = new ArrayList<>(200);
Date now = new Date();
for (int i = 0; i < 200; ++i) {
int delta = ThreadLocalRandom.current().nextInt(2, 10);
list.add(DateUtils.addMinutes(now, delta));
}
list.sort((x, y) -> {
int cmp = x.before(y) ? -1 : 1;
return cmp;
});
I have searched on Google, and found many similar issues (https://stackoverflow.com/questions/11441666/java-error-comparison-method-violates-its-general-contract), which say that the comparator does not meet transitivity rule. However, it seems that Date.before
should follow transitivity rule.
And I know the comparator has an issue when comparing two same dates. For any two same date, say d1
, d2
, both cmp(d1, d2)
and cmp(d2, d1)
return 1.
However, if we replace the comparator, always return 1, no error throw out. How surprising!
list.sort((x, y) -> 1);
In the above example, I created lots duplicated date which used to reproduce the error. Even though I know how to solve the issue, I still want to know why using before()
would fail.
By the way, I tested it on JDK 8 and 11, both failed.
专注分享java语言的经验与见解,让所有开发者获益!
评论