Skip to content
Advertisement

compareTo: treat two nulls as equal

I would like my compare method to work so that in the case where field1 == null in both objects, comparation would not be determined, but field2 would be checked, and so on. How to do it in the simplest way? The method below does not work well: when the fields from both objects are null, the comparison is always determined (without Ordering.natural().NullsFirst() I get NPE):

import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class MyClass implements Comparable<MyClass> {
   
    String field1;
    Integer field2;
    String field3;   

    @Override
    public int compareTo(MyClass myClass) {
        return ComparisonChain.start()
            .compare(field1, myClass.field1, Ordering.natural().nullsFirst())
            .compare(field2, myClass.field2, Ordering.natural().nullsFirst())
            .compare(field3, myClass.field3, Ordering.natural().nullsFirst())           
            .result(); 
    }
}

Advertisement

Answer

Having Ordering.natural().nullsFirst() as third parameter is the expected way.

The documentation shows it rather clearly:

public int compareTo(Foo that) {
  return ComparisonChain.start()
      .compare(this.aString, that.aString)
      .compare(this.anInt, that.anInt)
      .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
      .result();
}

Furthermore, ComparisonChain is in com.google.common.collect, which is annotated with @ParametersAreNonnullByDefault, and here are the complete definition of the two compare methods used for custom objects:

abstract ComparisonChain compare​(Comparable left, Comparable right)

And

abstract <T extends @Nullable Object> ComparisonChain compare​(T left, T right, Comparator comparator)

The first doesn’t have any parameter marked with @Nullable while the second, with the ordering does.

Therefore, there are no simpler way of doing what you do.

Advertisement