Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparable and Comparator contract with regards to null

Comparable contract specifies that e.compareTo(null) must throw NullPointerException.

From the API:

Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

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 comparing null and throwing NullPointerException?
  • Is it ever a good idea to even have to sort a List containing null elements, or is that a sure sign of a design error?
like image 381
polygenelubricants Avatar asked May 18 '10 15:05

polygenelubricants


People also ask

How does Comparator handle null values?

When both elements are null, then they are considered equal. When both elements are non-null, the specified Comparator determines the order. If specified comparator is null, then the returned comparator considers all non-null elements equal.

Can you use compareTo with null?

4.3. The compare() method in StringUtils class is a null-safe version of the compareTo() method of String class and handles null values by considering a null value less than a non-null value. Two null values are considered equal. The two methods can also be used with a nullIsLess option.

How do you know when to use comparable and Comparator?

1) Comparable provides a single sorting sequence. In other words, we can sort the collection on the basis of a single element such as id, name, and price. The Comparator provides multiple sorting sequences. In other words, we can sort the collection on the basis of multiple elements such as id, name, and price etc.

What is compared in the Comparator?

Comparable in Java is an object to compare itself with another object, whereas Comparator is an object for comparing different objects of different classes. Comparable provides the compareTo() method to sort elements in Java, whereas Comparator provides compare() method to sort elements in Java.


2 Answers

Is it ever a good idea to even have to sort a List containing null elements, or is that a sure sign of a design error?

Conceptually, null means "nothing", and placing nothing in a list seems weird to me. Also, the Java List contract states that

Some list implementations have restrictions on the elements that they may contain. For example, some implementations prohibit null elements

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.

like image 42
Anno v. Heimburg Avatar answered Oct 05 '22 12:10

Anno v. Heimburg


Comparable doesn't allow null simply because:

a.compareTo(b) == -b.compareTo(a) 

for all objects a and b where !a.equals(b). More specifically:

a.equals(b) ? b.equals(a) && a.compareTo(b) == 0 &&                   b.compareTo(a) == 0 && a.hashCode() == b.hashCode()             : !b.equals(a) && a.compareTo(b) != 0 &&                   a.compareTo(b) == -b.compareTo(a) 

must evaluate to true to satisfy the relevant contracts.

So null isn't allowed because you can't do:

null.compareTo(a) 

Comparator is more flexible so handling of null is an implementation-specific issue. Support it or not depending on what you want your Comparator to do.

like image 60
cletus Avatar answered Oct 05 '22 10:10

cletus