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]