2015-07-21 2 views
1

Я знаю, что многие ответы ответили на мой вопрос. В моем коде, исключение говорит, что «метод сравнения нарушает его общий договор», но я не знаю, что мой метод сравнения, как нарушает его общие contract.This мой код:Метод сравнения нарушает его общий контракт java7

public static List<Entry<Integer, Double>> sortMap(
    Map<Integer, Double> curMap, final boolean isDesc) { 
    List<Entry<Integer, Double>> res = new ArrayList<Entry<Integer, Double>>(); 
    for (Entry<Integer, Double> iter : curMap.entrySet()) { 
     res.add(iter); 
    } 
    Collections.sort(res, new Comparator<Entry<Integer, Double>>() { 
     public int compare(Entry<Integer, Double> o1, 
       Entry<Integer, Double> o2) { 
      if (o1.getValue() == o2.getValue()) { 
       return 0; 
      } else if (o1.getValue() > o2.getValue()) { 
       return isDesc ? -1 : 1; 
      } 
      return isDesc ? 1 : -1; 
     } 
    }); 
    return res; 
} 

ответ

2

Есть пара тонких вещей происходит Здесь. Это не обычная проблема с «сломанным компаратором», рассмотренная в другом месте в Stack Overflow. Хотя этот компаратор действительно сломан, его довольно сложно увидеть.

Первая проблема заключается в том, что компаратор несет основную ответственность за сравнение значений Double, то есть в штучной упаковке double значений. Принимая во внимание, что оператор > выполнит автоматическую распаковку и проведет цифровое сравнение содержащихся значений, оператор == проверит ссылочное равенство. В общем,

Double.valueOf(1.23) == Double.valueOf(1.23) // WARNING: reference comparison, not numeric! 

будет false. Если вы действительно хотите, чтобы проверить числовое равенство Double значений, вы должны были бы сделать

if (o1.getValue().doubleValue() == o2.getValue.doubleValue()) ... 

Это будет в основном работать, если ваш вход содержит только фактические числовые значения. Я подозреваю, однако, что ваш ввод содержит значения NaN, которые имеют неясное (даже бессмысленное) поведение. В частности, сравнение NaN с любым числовым значением ложно, а NaN сравнивает не равное себе! Это нарушает правила всех типов о числовых сравнениях; Действительно, NaN неупорядочен относительно действительных чисел. Вот почему алгоритм сортировки ломается, когда он встречает значения NaN.

(NaN является результатом деления 0.0 на 0.0, между прочим.)

Существует метод, который обрабатывает Double.compare(double d1, double d2)NaN разумно; он сортирует NaN значениями выше Double.POSITIVE_INFINITY. (Он также отличает положительный ноль от отрицательного нуля, но это вряд ли вызовет вашу проблему.) Существует сопутствующий метод Double.compareTo(Double), который сравнивает значения в ящике Double.

Я бы переписать компаратор так:

Collections.sort(res, new Comparator<Entry<Integer, Double>>() { 
    public int compare(Entry<Integer, Double> o1, 
         Entry<Integer, Double> o2) { 
     if (isDesc) { 
      return o2.getValue().compareTo(o1); 
     } else { 
      return o1.getValue().compareTo(o2); 
     } 
    } 
} 

Поскольку Double является Comparable самим, в Java-вы можете избежать написаний собственного компаратора с использованием методы полезности на Map.Entry. Вы можете также использовать метод по умолчанию sort() на List, который будет быстрее в целом:

if (isDesc) { 
    res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed()); 
} else { 
    res.sort(Map.Entry.comparingByValue()); 
} 

(К сожалению, вывод типа не совсем работа, поэтому вы должны обеспечить «тип свидетеля», чтобы получить обратный компаратор.)

Наконец, вы можете использовать оператор «бриллиант» и конструктор копирования ArrayList, чтобы скопировать записи в карты гораздо более сжато. Переписанная процедура выглядит так:

public static List<Entry<Integer, Double>> sortMap(
     Map<Integer, Double> curMap, final boolean isDesc) { 
    List<Entry<Integer, Double>> res = new ArrayList<>(curMap.entrySet()); 

    if (isDesc) { 
     res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed()); 
    } else { 
     res.sort(Map.Entry.comparingByValue()); 
    } 

    return res; 
} 
Смежные вопросы