Договор сравнения и компаратора относительно нулевого

Comparable контракт указывает, что e.compareTo(null) должен e.compareTo(null) NullPointerException .

Из API :

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

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

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

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

 List numbers = new ArrayList( Arrays.asList(3, 2, 1, null, null, 0) ); Comparator numbersComp = nullComparableComparator(); Collections.sort(numbers, numbersComp); System.out.println(numbers); // "[null, null, 0, 1, 2, 3]" List names = new ArrayList( Arrays.asList("Bob", null, "Alice", "Carol") ); Comparator namesComp = nullComparableComparator(); Collections.sort(names, namesComp); System.out.println(names); // "[null, Alice, Bob, Carol]" 

Поэтому вопросы:

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

    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, поэтому я должен сказать, что это приемлемое использование компаратора.

    Давайте будем гением компьютера.