2016-08-17 8 views
1

Я попробовал много возможных решений, указанный на сети хотите установить системное свойство и конвертировать в два раза, но все еще получаю ту же ошибку:Получение ошибки: Метод сравнения нарушает его генподряд

java.lang.IllegalArgumentException: Comparison method violates its general contract! 
    at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:835) 
    at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:453) 
    at java.util.ComparableTimSort.mergeForceCollapse(ComparableTimSort.java:392) 
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:191) 
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:146) 
    at java.util.Arrays.sort(Arrays.java:472) 
    at java.util.Collections.sort(Collections.java:155) 

Вот мой код:

 System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); 
     Collections.sort(docs, new Comparator<FeedDocument>() { 
      public int compare(FeedDocument o1, FeedDocument o2) { 

       int year1 = 0; 
       int year2 = 0; 
       int returnResult = 0; 
       if (o1.containsKey(FeedConstants.PUBLICATION_YEAR) 
         && o2.containsKey(FeedConstants.PUBLICATION_YEAR) 
         && o1.get(FeedConstants.PUBLICATION_YEAR) != null 
         && (o1.get(FeedConstants.PUBLICATION_YEAR) instanceof String) 
         && o2.get(FeedConstants.PUBLICATION_YEAR) != null 
         && (o2.get(FeedConstants.PUBLICATION_YEAR) instanceof String)) { 

        String firstyear = (String) o1.get((FeedConstants.PUBLICATION_YEAR)); 
        String secondyear = (String) o2.get((FeedConstants.PUBLICATION_YEAR)); 

        if (firstyear.equals(secondyear)) { 
         return 0; 
        } else if (firstyear != null && !firstyear.isEmpty() && secondyear != null 
          && !secondyear.isEmpty()) { 

         year1 = Integer.parseInt(firstyear.trim()); 

         year2 = Integer.parseInt(secondyear.trim()); 

         // int result = year2 - year1; 
         // if (result > 0) { 
         // returnResult = 1; 
         // } else if (result < 0) { 
         // returnResult = -1; 
         // } 
         return Double.compare(year2, year1); 
        } 

       } else { 
        returnResult = 0; 
       } 
       return returnResult; 
      } 
     }); 
+1

Возможный дубликат [«Метод сравнения нарушает его общий контракт!»] (Http://stackoverflow.com/questions/8327514/comparison-method-violates-its-general-contract) – bradimus

+0

Просто FYI 'instanceof' возвращает' false 'если его левый аргумент равен нулю, нет необходимости в другой проверке. – mszymborski

+0

Да, вы можете комбинировать 'o1.containsKey (FeedConstants.PUBLICATION_YEAR) && o1.get (FeedConstants.PUBLICATION_YEAR)! = Null && o1.get (FeedConstants.PUBLICATION_YEAR) instanceof String' в просто' o1.get (FeedConstants.PUBLICATION_YEAR) instanceof String'. У вас также есть дополнительные ненужные проверки в будущем: 'firstyear! = Null' и' secondyear! = Null'. Они просто загромождают код и затрудняют его выполнение. – mapeters

ответ

0

Edward Peters' answer правильно диагностировать проблему, как ваш метод compare не производит последовательные (переходные) результаты.

Лучший способ решить это что-то вроде следующего в вашем compare метод:

if (o1.get(FeedConstants.PUBLICATION_YEAR) instanceof String) { 
    if (o2.get(FeedConstants.PUBLICATION_YEAR) instanceof String) { 
     // Perform the comparison here like you are 
    } else { 
     /* 
     * This could also be 1, the key is to have it consistent 
     * so the final sorted list clearly separates the FeedDocuments 
     * with a String PUBLICATION_YEAR and those without one. 
     */ 
     return -1; 
    } 
} else if (o2.get(FeedConstants.PUBLICATION_YEAR) instanceof String) { 
    /* 
    * In this case, o1 doesn't have a String PUBLICATION_YEAR and o2 
    * does, so this needs to be the opposite of the return value 
    * 6 lines up to be consistent. 
    */ 
    return 1; 
} else { 
    /* 
     * Consider all FeedDocuments without a String PUBLICATION_YEAR 
     * to be equivalent, otherwise you could do some other comparison 
     * on them here if you wanted. 
     */ 
    return 0; 
} 

Ключ, если вы заботитесь только о подмножестве список сортируется (в FeedDocument с с String год публикации, то вам нужно сначала отделить их от остальной части списка, которую вы не заботитесь о сортировке (возвращая либо 1, либо -1, когда один из FeedDocument s имеет год публикации String, а другой нет). Затем вы можете отсортировать требуемое подмножество без несогласованных результатов.

+0

Я не понял/* * В этом случае o1 не имеет строки PUBLICATION_YEAR и o2 *, поэтому это должно быть противоположно возвращаемому значению * 6 строк, чтобы быть последовательными. */ –

+0

@TanuGarg в строке 'return -1', мы определили, что' o1' имеет год публикации, а 'o2' - нет. Итак, 'return -1' говорит, что' o1' (и все 'FeedDocument' s с годом публикации) должны появиться перед теми, у которых нет года публикации. В строке 'return 1' мы определили, что' o1' не имеет год публикации, но 'o2' делает, что является противоположным сценарием первого. Поэтому, говоря «return 1', выкладывает' o1' (и все 'FeedDocument' без года публикации) после тех, у кого год публикации, что соответствует тому, что произошло на строке 'return -1'. – mapeters

+1

Понял. Спасибо за объяснение, также была устранена ошибка. –

4

Довольно уверен, что я знаю, что здесь происходит ...

Suppse:

o1.get(FeedConstants.PUBLICATION_YEAR) != null 
o2.get(FeedConstants.PUBLICATION_YEAR) == null 
o3.get(FeedConstants.PUBLICATION_YEAR) != null 

Тогда:

compare (o1, o2); //returns 0 
compare (o2, o3); //returns 0 
compare (o1, o3); //returns not 0 

Так вы утверждая o1 == o2 == o3 но o1 != o3

+0

Как решить? Пожалуйста, предложите –

+0

@TanuGarg. Вам просто нужно сделать так, чтобы одно значение null не возвращало равенства. Стандарт, который я обычно использую, - «Если они оба равны нулю, они равны, если один из них равен нулю, он будет автоматически меньше, если ни один из них не является нормальным. –

+0

Спасибо, Эдвард. Ошибка решена. –