2010-05-18 5 views
34

Comparable договор устанавливает, что e.compareTo(null) должен бросить NullPointerException.Договор со сравнительным и компаратором по отношению к нулю

От the API:

Обратите внимание, что null не является экземпляром какого-либо класса, и e.compareTo(null) должен бросить NullPointerException несмотря на то, e.equals(null) возвращается false.

С другой стороны, Comparator API ничего не упоминает о том, что должно произойти при сравнении null. Рассмотрим следующую попытку обобщенного метода, который принимает Comparable и возвращает Comparator для него, который ставит null в качестве минимального элемента.

static <T extends Comparable<? super T>> Comparator<T> nullComparableComparator() { 
    return new Comparator<T>() { 
     @Override public int compare(T el1, T el2) { 
     return 
      el1 == null ? -1 : 
      el2 == null ? +1 : 
      el1.compareTo(el2); 
     } 
    }; 
} 

Это позволяет нам сделать следующее:

List<Integer> numbers = new ArrayList<Integer>(
    Arrays.asList(3, 2, 1, null, null, 0) 
); 
Comparator<Integer> numbersComp = nullComparableComparator(); 
Collections.sort(numbers, numbersComp); 
System.out.println(numbers); 
// "[null, null, 0, 1, 2, 3]" 

List<String> names = new ArrayList<String>(
    Arrays.asList("Bob", null, "Alice", "Carol") 
); 
Comparator<String> namesComp = nullComparableComparator(); 
Collections.sort(names, namesComp); 
System.out.println(names); 
// "[null, Alice, Bob, Carol]" 

Так вопросы:

  • Является ли это приемлемо использование Comparator, или он нарушает неписаные правила в отношении при сравнении null и метании NullPointerException?
  • Не стоит ли даже сортировать List, содержащий null элементов, или это верный признак ошибки дизайна?
+0

Примечание для других, имеющих проблемы с компиляцией этого кода: есть ошибка в javac, но она компилируется и запускается в Eclipse !!! http://stackoverflow.com/questions/2858799/generics-compiles-and-runs-in-eclipse-but-doesnt-compile-in-javac – polygenelubricants

ответ

23

Comparable не позволяет null просто потому, что:

a.compareTo(b) == -b.compareTo(a) 

для всех объектов a и b где !a.equals(b). Более конкретно:

a.equals(b) ? b.equals(a) && a.compareTo(b) == 0 && 
        b.compareTo(a) == 0 && a.hashCode() == b.hashCode() 
      : !b.equals(a) && a.compareTo(b) != 0 && 
        a.compareTo(b) == -b.compareTo(a) 

должны вычисляться true для удовлетворения соответствующих контрактов.

Так null не допускается, так как вы не можете сделать:

null.compareTo(a) 

Comparator является более гибким, так перевалка null является вопросом реализации. Поддержите это или нет, в зависимости от того, что вы хотите делать Comparator.

+1

Тест 'ab == -ba' убедителен, но я предпочитаю Аргумент API: 'Comparable' определяет естественный порядок для экземпляров класса, а' null' просто не является экземпляром какого-либо класса. Если бы вы обратились к «null» в «List», в первую очередь? Надеюсь, это не «субъективный». – polygenelubricants

+0

(Такое уравнение a.compareTo (b) == -b.compareTo (a) не обязательно корректно для каждого типа. Возвращаемое значение compareTo() не должно представлять разницу в любых полях из двух объектов. это метод, в котором compareTo() запрограммирован очень часто, это не очень хорошая идея! - Рассчитанная разница может переполняться, а затем приводить к неправильному положительному/отрицательному значению. (Лучше буквально возвращать -1, 0 или 1 из compareTo() только. - Это не так ласково, но правильно.)) – Nico

8

Всегда ли нужно сортировать список, содержащий нулевые элементы, или это верный признак ошибки дизайна?

Концептуально, null означает «ничего», и размещение ничего в списке кажется мне странным. Кроме того, в контракте Java List указано, что

Некоторые реализации списков имеют ограничения на элементы, которые они могут содержать.Например, некоторые реализации запрещают нулевые элементы

поэтому реализация List на Java не требуется даже для поддержки нулевых элементов. Подводя итог, если у вас нет веской причины помещать нуль в список, не делайте этого, и если вы это сделаете, проверьте, что он действительно работает так, как ожидалось.

+1

+1 для того, чтобы поймать, что поддержка 'null' в' List' даже не является обязательной. – polygenelubricants

4

ли когда-либо хорошая идея, даже придется отсортировать список, содержащий пустые элементы, или это верный признак ошибки проектирования?

Ну, вероятно, для списка не имеет смысла содержать нулевой объект, но, возможно, ваш список содержит «бизнес-объект», и вы можете сортировать по различным свойствам бизнес-объекта, некоторые из которых могут содержат нули.

Является ли это приемлемо использование Компаратора

BeanComparator позволяет сортировать по Собствености в бизнес-объекте, даже если свойство содержит нуль, так что я должен был бы сказать, что это приемлемое использование компаратора.

+0

Какой «BeanComparator»? Это не часть JDK, мы не можем рассчитывать на это, чтобы доказать что-либо в этом отношении. – ymajoros

+0

@ymajoros, 'Какой« BeanComparator »- это тот, который найден в ссылке. – camickr

+0

, который не является частью JDK ... Кроме того, что это плохая идея (небезопасно, ломается при рефакторинге и т. Д.). – ymajoros

Смежные вопросы