comparator with null values
We have some code which sorts a list of addresses based on the distance between their coordinates. this is done through collections.sort with a custom comparator.
However from time to time an address without coordinates is in the list causing a NullPointerException. My initial idea to fix this was to have the comparator return 0 as distance for addresses where at least one of the coordinates is null. I fear this might lead to corruption of the order the 'valid' elements in the list.
so is returning a '0' values for null data in a comparator ok, or is there a cleaner way to resolve this?
Handle it like null
means infinitely far away. Thus:
comp(1234, null) == -1
comp(null, null) == 0
comp(null, 1234) == 1
With this, you get a consistent ordering.
Just to expand on Willi Schönborn's answer, I came here to say that google-collections is exactly what you're after here.
In the general case, you can just write your own Comparator
to ignore nulls (assume non-null, so it can concentrate on the important logic), and then use Ordering to handle the nulls:
Collections.sort(addresses, Ordering.from(new AddressComparator()).nullsLast());
In your case, though, it's data WITHIN the Address (the Coordinates) that is being used to sort, right? google-collections is even more useful in this case. So you might have something more like:
// 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
then when you want to sort:
Collections.sort(addresses,
Ordering.from(COORDINATE_SORTER)
.nullsLast()
.onResultOf(ADDRESS_TO_COORDINATES));
and that's where the power of google-collections really starts to pay off.
If you are using Java 8, you have 2 new static methods in the Comparator class, which come in handy:
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator)
The comparison will be null safe and you can choose where to place the null values in the sorted sequence.
The following example:
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 + "] "));
will print: [null] [null] [] [Chimp] [banana] [eat] [run] [sleep] [smile] [throw banana peel]