Контракт сравнимый и компаратор по нулю

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.

Другие вопросы по тегам