An error "Comparison method violates its general contract" when compare Date via before()

huangapple 未分类评论48阅读模式
英文:

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 应该是遵循传递性规则的。

我知道这个比较器在比较两个相同日期时会有问题。对于任意两个相同的日期,比如 d1d2cmp(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&lt;Date&gt; list = new ArrayList&lt;&gt;(200);

Date now = new Date();
for (int i = 0; i &lt; 200; ++i) {
    int delta = ThreadLocalRandom.current().nextInt(2, 10);
    list.add(DateUtils.addMinutes(now, delta));
}

list.sort((x, y) -&gt;  {
    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) -&gt; 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.

huangapple
  • 本文由 发表于 2020年5月29日 17:12:36
  • 转载请务必保留本文链接:https://java.coder-hub.com/62082450.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定