Error : Comparison method violates its general contract

Error : Comparison method violates its general contract

我知道有很多与此主题相关的问题,但我无法完全理解导致此错误的原因

 Collections.sort(noteList,new Comparator<ClassNote>(){
        @Override
        public int compare(ClassNote b, ClassNote a) {
           DateFormat formatter = new SimpleDateFormat("MMMM dd HH:mm", Locale.US);
           try {
               Date date2 = formatter.parse(b.getCallDate());
               Date date1 = formatter.parse(a.getCallDate());
               if ( date1 == null ) {
                   if ( date2 == null) {
                       return 0;
                   }
                   return 1;
               }
               if ( date2 == null ) {
                   return -1;
               }
               return date2.compareTo(date1);
           } catch (ParseException e) {
               e.printStackTrace();
               return 1;
           }
        }
    });

有谁知道为什么它不起作用以及如何解决它?

如果比较 ClassNoteab 的两个实例,解析其中一个将抛出异常:

compare(a, b)将returna变大

compare(b, a)将returnb变大

比较return值不一致。

我认为在这种情况下最好的计划是,与其关注 "How do I make my comparison function consistent",不如问 "What do I want a sorted array to look like"?当您正在处理特殊情况时,这一点尤其重要。找出正确的顺序后,编写一个比较函数来为您提供该顺序。

在这里,您要处理的 ClassNote 三类:

  1. ClassNote 个具有有效日期的对象
  2. ClassNote 解析日期的对象 returns null
  3. ClassNote 个解析日期抛出异常的对象

类别 1 很简单:您希望对象按日期排序。 (你还必须弄清楚当两个 ClassNote 具有相同日期时会发生什么,但在这种情况下你可能不关心顺序,这很好。在某些情况下,你可能想要相同的项目要按其他字段排序的日期。)

对于#2 和#3,您希望它们出现在结果中的什么位置?到目前为止,看起来您首先需要 null 个,但您还没有处理解析异常。我可以看到两种简单的方法:

  1. null 视为异常。然后所有的空值和异常情况将按某种顺序出现并混合在一起,但这可能没问题。
  2. 将它们分组,使 #2 项目排在第一位,然后是 #3,然后是具有有效日期的项目。或者反过来:#3,然后是#2,然后是有效日期。

两种方法都可以,但您必须根据自己的需要做出决定。

假设您采用方法 1。现在你必须安排事情,以便当你比较 #2 项和 #3 项时,结果为 0;当您将 #2 或 #3 项目与 #1 进行比较时,#2 或 #3 总是更少。您可以修改现有代码

 Date date2 = formatter.parse(b.getCallDate());
 Date date1 = formatter.parse(a.getCallDate());

对此:

 Date date2 = parseOrReturnNull(b.getCallDate());
 Date date1 = parseOrReturnNull(a.getCallDate());

其中 parseOrReturnNull 是一个辅助方法,它使用 formatter.parse(),捕获 ParseException,如果有 returns null例外。现在您的其余逻辑将确保空值和解析异常将以相同的方式处理以进行排序。

如果您想分别对 null 和异常进行分组,一种解决方案是添加一个应用于每个 ClassNote 的 "category" 变量。该类别将以正确的顺序指示 ClassNote 属于哪个类别:因此,如果您首先想要 nulls,然后是例外,然后是有效日期,则可以将 [=17] 的类别设为 0 =], 1 表示例外,2 表示有效日期。 (更好的是,使用 enum)。然后,对于每个日期,您将计算类别和 date。事实上,最好声明一个新的 class:

class ComparisonDate {
    int category;  // or enum
    Date date;     // meaningful only if the date is valid
}

使用带有 ClassNote 和 returns 和 ComparisonDate 的辅助方法。然后你可以用这样的代码比较两个 ComparisonDates:

if (cd1.category != cd2.category) {
    return Integer.compare(cd1.category, cd2.category);
} else if (cd1.category == 2) {    // 2 means they have valid dates
    return cd1.date.compareTo(cd2.date);
} else {        // ComparisonDates are in same category and dates aren't
                // meaningful
    return 0;   // so treat them as equal
}

我可能把 cd1cd2 调换了,但你可以解决这个问题。