比较方法违反了它的一般契约——如何避免

Comparison method violates its general contract - how to avoid it

我知道这个问题可能有一些非常好的解释,但我仍然无法将其应用到我的代码中。在我的案例中如何避免该错误?这是我的代码:

        sampleList.sort((o1, o2) -> {
            try {
                if (o1.getDate() == null || o2.getDate() == null) return 0;
                int i = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy").parse(o1.getDate()).compareTo(new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy").parse(o2.getDate()));
                return i;
            } catch (ParseException e) {
                logger.error("Sorting failed", e);
            }
            return 0;
        });

sampleList 是一个列表类型,包含字符串形式的日期。这是我得到的一个例外:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(Unknown Source)
    at java.util.TimSort.mergeAt(Unknown Source)
    at java.util.TimSort.mergeCollapse(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at 

如果您有解决问题的建议,请与我分享。谢谢。

compare(T o1, T o2) 的 javadoc 说:

the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

您的实施未能满足合同的该部分。

如果您有 x = null, y = 1, z = 2,您对 "null equals anything" 的实施意味着:

compare(x, y) == 0   // Precondition met
//    0

sgn(compare(x, z)) == sgn(compare(y, z))   // Contract violated!
//      0                   -1

您的比较器无法正确处理空值和无法解析的日期。考虑以下情况:

假设您有两个非空日期 d1 和 d2 以及一个空日期 d3。 假设 d1 > d2.

你因此有

d1 > d2
d1 == d3
d2 == d3

因此,如果 d1 和 d2 都等于 d3,则它们也应该彼此相等,但它们不是。

首先将所有字符串转换为日期或 null。

然后使用将所有空值视为大于(或小于)所有非空值的比较器。 Comparator 具有将非空对象的比较器转换为处理空值的比较器的实用方法,方法是将它们全部放在最前面或最后。