Comparable
contract specifies that e.compareTo(null)
must throw NullPointerException
.
From the API:
Note that
null
is not an instance of any class, ande.compareTo(null)
should throw aNullPointerException
even thoughe.equals(null)
returnsfalse
.
On the other hand, Comparator
API mentions nothing about what needs to happen when comparing null
. Consider the following attempt of a generic method that takes a Comparable
, and return a Comparator
for it that puts null
as the minimum element.
static <T extends Comparable<? super T>> Comparator<T> nullComparableComparator() {
return new Comparator<T>() {
@Override public int compare(T el1, T el2) {
return
el1 == null ? -1 :
el2 == null ? +1 :
el1.compareTo(el2);
}
};
}
This allows us to do the following:
List<Integer> numbers = new ArrayList<Integer>(
Arrays.asList(3, 2, 1, null, null, 0)
);
Comparator<Integer> numbersComp = nullComparableComparator();
Collections.sort(numbers, numbersComp);
System.out.println(numbers);
// "[null, null, 0, 1, 2, 3]"
List<String> names = new ArrayList<String>(
Arrays.asList("Bob", null, "Alice", "Carol")
);
Comparator<String> namesComp = nullComparableComparator();
Collections.sort(names, namesComp);
System.out.println(names);
// "[null, Alice, Bob, Carol]"
So the questions are:
- Is this an acceptable use of a
Comparator
, or is it violating an unwritten rule regarding comparingnull
and throwingNullPointerException
? - Is it ever a good idea to even have to sort a
List
containingnull
elements, or is that a sure sign of a design error?
Well, it probably doesn't make sense for the list to contain a null Object, but maybe your List contains a "business object" and you can sort on different properties of the business object, some of which may contain nulls.
The BeanComparator allows you to sort on a propery in a business object even if the property contains null, so I would have to say it is an acceptable use of a Comparator.
Comparable
doesn't allownull
simply because:for all objects
a
andb
where!a.equals(b)
. More specifically:must evaluate to
true
to satisfy the relevant contracts.So
null
isn't allowed because you can't do:Comparator
is more flexible so handling ofnull
is an implementation-specific issue. Support it or not depending on what you want yourComparator
to do.Conceptually, null means "nothing", and placing nothing in a list seems weird to me. Also, the Java List contract states that
so a List implementation in Java is not even required to support null elements at all. To sum up, if you do not have a good reason to put null into a list, don't, and if you do, test that it actually works as expected.