Контракт сравнимый и компаратор по нулю
Comparable
в договоре указано, что e.compareTo(null)
должен бросить NullPointerException
,
Из 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
элементы, или это верный признак ошибки проектирования?
3 ответа
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
сделать.
Является ли когда-нибудь хорошей идеей даже сортировать список, содержащий нулевые элементы, или это верный признак ошибки проектирования?
Концептуально, null означает "ничто", и размещение ничего в списке кажется мне странным. Кроме того, в контракте Java List указано, что
Некоторые реализации списка имеют ограничения на элементы, которые они могут содержать. Например, некоторые реализации запрещают нулевые элементы
поэтому реализация List в Java даже не требуется вообще поддерживать нулевые элементы. Подводя итог, если у вас нет веских оснований для добавления нуля в список, не проверяйте, если он есть, то, что он действительно работает, как ожидалось.
Является ли когда-нибудь хорошей идеей даже сортировать список, содержащий нулевые элементы, или это верный признак ошибки проектирования?
Что ж, вероятно, не имеет смысла, чтобы список содержал нулевой объект, но, возможно, ваш список содержит "бизнес-объект", и вы можете сортировать по различным свойствам бизнес-объекта, некоторые из которых могут содержать нули.
Это приемлемое использование компаратора
BeanComparator позволяет вам сортировать свойства в бизнес-объекте, даже если свойство содержит значение null, поэтому я должен сказать, что это приемлемое использование Comparator.