Comparator.comparing() без nullsFirst — NPE на первом null

Сортировка списка по полю, которое иногда null, кажется безопасной операцией. Comparator.comparing(Order::getShippedAt) компилируется и работает на тестовых данных, где даты у всех заказов заполнены.

В проде часть заказов ещё не отправлена, shippedAt = null. Comparator.comparing() внутри вызывает compareTo() на возвращённых значениях, а Comparable для дат не умеет сравнивать с null — это NullPointerException прямо в момент sort(), причём стектрейс укажет на TimSort, а не на ваш код.

orders.sort( Comparator.comparing( Order::getShippedAt, Comparator.nullsFirst( Comparator.naturalOrder() ) ) );

Ловушка: nullsFirst и nullsLast сами оборачивают компаратор, а не заменяют его — без вложенного naturalOrder() или своего компаратора код не скомпилируется. Ещё спросят: что если сортировка идёт по нескольким полям через thenComparing, а null может быть в любом из них? Тогда nullsFirst/nullsLast нужно на каждом уровне отдельно, дефолт не наследуется дальше по цепочке.

Comparable молчит про null в контракте — это забота вызывающего кода, не JVM.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки