Ответ 1
Обращаться так, как null
означает бесконечно далеко. Таким образом:
-
comp(1234, null) == -1
-
comp(null, null) == 0
-
comp(null, 1234) == 1
При этом вы получаете последовательный порядок.
У нас есть код, который сортирует список адресов на основе расстояния между их координатами. это делается через collection.sort с пользовательским компаратором.
Однако время от времени в списке появляется адрес без координат, вызывающий исключение NullPointerException. Моя первоначальная идея исправить это состояла в том, чтобы компаратор возвращал 0 как расстояние для адресов, где хотя бы одна из координат равна нулю. Я боюсь, что это может привести к тому, что порядок порядка станет "правильным" в списке.
поэтому возвращает значения "0" для нулевых данных в компараторе в порядке или есть более чистый способ разрешить это.
Обращаться так, как null
означает бесконечно далеко. Таким образом:
comp(1234, null) == -1
comp(null, null) == 0
comp(null, 1234) == 1
При этом вы получаете последовательный порядок.
Чтобы развернуть ответ Вилли Шённборна, я пришел сюда, чтобы сказать, что google-collections - это именно то, что вы здесь делаете.
В общем случае вы можете просто написать свой собственный Comparator
, чтобы игнорировать значения NULL (предположим, что они не равны нулю, поэтому могут сосредоточиться на важной логике), а затем использовать Ordering для обработки нулей:
Collections.sort(addresses, Ordering.from(new AddressComparator()).nullsLast());
В вашем случае, однако, это данные WITHIN Address (Координаты), которые используются для сортировки, правильно? google-коллекции в этом случае еще более полезны. Таким образом, у вас может быть что-то большее:
// Seems verbose at first glance, but you'll probably find yourself reusing
// this a lot and it will pay off quickly.
private static final Function<Address, Coordinates> ADDRESS_TO_COORDINATES =
new Function<Address, Coordinates>() {
public Coordinates apply(Address in) {
return in.getCoordinates();
}
};
private static final Comparator<Coordinates> COORDINATE_SORTER = .... // existing
тогда, когда вы хотите сортировать:
Collections.sort(addresses,
Ordering.from(COORDINATE_SORTER)
.nullsLast()
.onResultOf(ADDRESS_TO_COORDINATES));
и что, когда мощь google-коллекций действительно начинает окупаться.
Я считаю, что все, что вы пытаетесь сделать, чтобы "сделать хорошо", координаты null
- это просто обклеивание трещин. Вам действительно нужно найти и исправить ошибки, которые вводят ложные координаты null
.
По моему опыту, заражения ошибок NPE часто вызывают следующие плохие привычки кодирования:
null
, чтобы избежать создания пустых массивов или коллекций,null
, когда должно быть выбрано исключение, илиnull
для представления "нет значения", когда есть лучшее решение.(Более эффективные решения проблемы "нет значения" обычно включают в себя переписывание кода, так что вам не нужно представлять это и/или использовать ненулевое значение, например, пустую строку, специальный экземпляр, зарезервированное значение Вы не всегда можете найти лучшее решение, но часто можете это сделать.)
Если это описывает ваше приложение, вы должны тратить время на устранение проблем с кодом, вместо того, чтобы думать о способах скрыть NPE.
Мое решение (может быть полезно для кого-то, смотрящего здесь) - выполнить нормальное сравнение, при этом нулевые значения заменяются не на 0, а максимальное возможное значение (например, Integer.MAX_VALUE). Возвращение 0 несовместимо, если у вас есть значения, которые сами являются 0. Вот правильный пример:
public int compare(YourObject lhs, YourObject rhs) {
Integer l = Integer.MAX_VALUE;
Integer r = Integer.MAX_VALUE;
if (lhs != null) {
l = lhs.giveMeSomeMeasure();
}
if (rhs != null) {
r = rhs.giveMeSomeMeasure();
}
return l.compareTo(r);
}
Я просто хотел добавить, что вам не нужно максимальное значение для integer. Это зависит от того, что может вернуть метод giveMeSomeMeasure(). Если, например, вы сравниваете градусы Цельсия для погоды, вы можете установить l и r на -300 или +300, в зависимости от того, где вы хотите установить нулевые объекты - в голову или хвост списка.
Вероятно, вы не хотите возвращать 0, так как это означает, что адреса являются эквидистантными, и вы действительно не знаете. Это довольно классическая проблема, когда вы пытаетесь справиться с плохими входными данными. Я не считаю своей обязанностью компаратора пытаться определить, насколько далеко адрес находится в реальных условиях, когда вы не знаете расстояние. Я бы удалил эти адреса из списка перед сортировкой.
Шок должен был переместить их в нижнюю часть списка (но это уродливо!)
Нет, нет более чистого способа. Возможно:
Но что еще более важно - попробуйте избавиться от/заполнить недостающие координаты или, лучше: не помещать адреса с отсутствующими координатами в списке.
Собственно, не помещать их в список является наиболее логичным поведением. Если вы поместите их в список, результат не будет фактически упорядочен по расстоянию.
Вы можете создать другой список, содержащий адреса с отсутствующими координатами, и дать понять, кому нужна эта информация (конечный пользователь, пользователь API), что первый список содержит только адреса с необходимыми данными, а второй список содержит адреса, в которых отсутствует требуемая информация.
Вместо того, чтобы рассматривать это как техническую проблему с компаратором, лучше снова взглянуть на требования: что вы действительно пытаетесь сделать здесь, что вы собираетесь делать с этим отсортированным списком?
Как вы уже поняли, всегда возвращается 0, когда один из них является нулевым, здесь не очень хорошая идея; это может повредить результат. Но то, что вы должны делать, зависит от того, что вам нужно, а не от того, что другие обычно делают/нуждаются. Как ваша программа ведет себя с адресами, у которых нет местоположения (так, что пользователь увидит), не должно зависеть от некоторых технических деталей, таких как "лучшая практика" для компараторов. (Для меня, спрашивая, что такое "лучшая практика" здесь, звучит как спрашивать, каковы "лучшие требования" ).
Я лично ненавижу общаться со специальными нулевыми случаями всюду в моих компараторах, поэтому я искал более чистую оценку и, наконец, нашел коллекцию google. Их заказ просто потрясающий. Они поддерживают составные компараторы, предлагают сортировать нули до вершины и до конца и позволяют выполнять определенные функции перед сравнением. Написание компараторов никогда не было так просто. Вы должны попробовать.
Если вы используете Java 8, у вас есть 2 новых статических метода в классе Comparator, которые пригодится:
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator)
Сравнение будет небезопасным, и вы можете выбрать, где разместить нулевые значения в отсортированной последовательности.
Следующий пример:
List<String> monkeyBusiness = Arrays.asList("Chimp", "eat", "sleep", "", null, "banana",
"throw banana peel", null, "smile", "run");
Comparator<? super String> comparator = (a, b) -> a.compareTo(b);
monkeyBusiness.stream().sorted(Comparator.nullsFirst(comparator))
.forEach(x -> System.out.print("[" + x + "] "));
напечатает: [null] [null] [] [Chimp] [банан] [есть] [пробег] [сон] [улыбка] [бросить банановую кожуру]