[java] How to simplify a null-safe compareTo() implementation?

I'm implementing compareTo() method for a simple class such as this (to be able to use Collections.sort() and other goodies offered by the Java platform):

public class Metadata implements Comparable<Metadata> {
    private String name;
    private String value;

// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}

I want the natural ordering for these objects to be: 1) sorted by name and 2) sorted by value if name is the same; both comparisons should be case-insensitive. For both fields null values are perfectly acceptable, so compareTo must not break in these cases.

The solution that springs to mind is along the lines of the following (I'm using "guard clauses" here while others might prefer a single return point, but that's beside the point):

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(Metadata other) {
    if (this.name == null && other.name != null){
        return -1;
    }
    else if (this.name != null && other.name == null){
        return 1;
    }
    else if (this.name != null && other.name != null) {
        int result = this.name.compareToIgnoreCase(other.name);
        if (result != 0){
            return result;
        }
    }

    if (this.value == null) {
        return other.value == null ? 0 : -1;
    }
    if (other.value == null){
        return 1;
    }

    return this.value.compareToIgnoreCase(other.value);
}

This does the job, but I'm not perfectly happy with this code. Admittedly it isn't very complex, but is quite verbose and tedious.

The question is, how would you make this less verbose (while retaining the functionality)? Feel free to refer to Java standard libraries or Apache Commons if they help. Would the only option to make this (a little) simpler be to implement my own "NullSafeStringComparator", and apply it for comparing both fields?

Edits 1-3: Eddie's right; fixed the "both names are null" case above

About the accepted answer

I asked this question back in 2009, on Java 1.6 of course, and at the time the pure JDK solution by Eddie was my preferred accepted answer. I never got round to changing that until now (2017).

There are also 3rd party library solutions—a 2009 Apache Commons Collections one and a 2013 Guava one, both posted by me—that I did prefer at some point in time.

I now made the clean Java 8 solution by Lukasz Wiktor the accepted answer. That should definitely be preferred if on Java 8, and these days Java 8 should be available to nearly all projects.

This question is related to java refactoring comparison null compareto

The answer is


You can simply use Apache Commons Lang:

result = ObjectUtils.compare(firstComparable, secondComparable)

I know that it may be not directly answer to your question, because you said that null values have to be supported.

But I just want to note that supporting nulls in compareTo is not in line with compareTo contract described in official javadocs for Comparable:

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.

So I would either throw NullPointerException explicitly or just let it be thrown first time when null argument is being dereferenced.


I always recommend using Apache commons since it will most likely be better than one you can write on your own. Plus you can then do 'real' work rather then reinventing.

The class you are interested in is the Null Comparator. It allows you to make nulls high or low. You also give it your own comparator to use when the two values are not null.

In your case you can have a static member variable that does the comparison and then your compareTo method just references that.

Somthing like

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}

Even if you decide to roll your own, keep this class in mind since it is very useful when ordering lists thatcontain null elements.


You could design your class to be immutable (Effective Java 2nd Ed. has a great section on this, Item 15: Minimize mutability) and make sure upon construction that no nulls are possible (and use the null object pattern if needed). Then you can skip all those checks and safely assume the values are not null.


I always recommend using Apache commons since it will most likely be better than one you can write on your own. Plus you can then do 'real' work rather then reinventing.

The class you are interested in is the Null Comparator. It allows you to make nulls high or low. You also give it your own comparator to use when the two values are not null.

In your case you can have a static member variable that does the comparison and then your compareTo method just references that.

Somthing like

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}

Even if you decide to roll your own, keep this class in mind since it is very useful when ordering lists thatcontain null elements.


See the bottom of this answer for updated (2013) solution using Guava.


This is what I ultimately went with. It turned out we already had a utility method for null-safe String comparison, so the simplest solution was to make use of that. (It's a big codebase; easy to miss this kind of thing :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

This is how the helper is defined (it's overloaded so that you can also define whether nulls come first or last, if you want):

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

So this is essentially the same as Eddie's answer (although I wouldn't call a static helper method a comparator) and that of uzhin too.

Anyway, in general, I would have strongly favoured Patrick's solution, as I think it's a good practice to use established libraries whenever possible. (Know and use the libraries as Josh Bloch says.) But in this case that would not have yielded the cleanest, simplest code.

Edit (2009): Apache Commons Collections version

Actually, here's a way to make the solution based on Apache Commons NullComparator simpler. Combine it with the case-insensitive Comparator provided in String class:

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

Now this is pretty elegant, I think. (Just one small issue remains: the Commons NullComparator doesn't support generics, so there's an unchecked assignment.)

Update (2013): Guava version

Nearly 5 years later, here's how I'd tackle my original question. If coding in Java, I would (of course) be using Guava. (And quite certainly not Apache Commons.)

Put this constant somewhere, e.g. in "StringUtils" class:

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

Then, in public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

Of course, this is nearly identical to the Apache Commons version (both use JDK's CASE_INSENSITIVE_ORDER), the use of nullsLast() being the only Guava-specific thing. This version is preferable simply because Guava is preferable, as a dependency, to Commons Collections. (As everyone agrees.)

If you were wondering about Ordering, note that it implements Comparator. It's pretty handy especially for more complex sorting needs, allowing you for example to chain several Orderings using compound(). Read Ordering Explained for more!


I was looking for something similar and this seemed a bit complicated so I did this. I think it's a little easier to understand. You can use it as a Comparator or as a one liner. For this question you would change to compareToIgnoreCase(). As is, nulls float up. You can flip the 1, -1 if you want them to sink.

StringUtil.NULL_SAFE_COMPARATOR.compare(getName(), o.getName());

.

public class StringUtil {
    public static final Comparator<String> NULL_SAFE_COMPARATOR = new Comparator<String>() {

        @Override
        public int compare(final String s1, final String s2) {
            if (s1 == s2) {
                //Nulls or exact equality
                return 0;
            } else if (s1 == null) {
                //s1 null and s2 not null, so s1 less
                return -1;
            } else if (s2 == null) {
                //s2 null and s1 not null, so s1 greater
                return 1;
            } else {
                return s1.compareTo(s2);
            }
        }
    }; 

    public static void main(String args[]) {
        final ArrayList<String> list = new ArrayList<String>(Arrays.asList(new String[]{"qad", "bad", "sad", null, "had"}));
        Collections.sort(list, NULL_SAFE_COMPARATOR);

        System.out.println(list);
    }
}

If you want a simple Hack:

arrlist.sort((o1, o2) -> {
    if (o1.getName() == null) o1.setName("");
    if (o2.getName() == null) o2.setName("");

    return o1.getName().compareTo(o2.getName());
})

if you want put nulls to end of the list just change this in above metod

return o2.getName().compareTo(o1.getName());

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Comparator;

public class TestClass {

    public static void main(String[] args) {

        Student s1 = new Student("1","Nikhil");
        Student s2 = new Student("1","*");
        Student s3 = new Student("1",null);
        Student s11 = new Student("2","Nikhil");
        Student s12 = new Student("2","*");
        Student s13 = new Student("2",null);
        List<Student> list = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s11);
        list.add(s12);
        list.add(s13);

        list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder())));

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }


    }

}

output is

Student [name=*, id=1]
Student [name=*, id=2]
Student [name=Nikhil, id=1]
Student [name=Nikhil, id=2]
Student [name=null, id=1]
Student [name=null, id=2]

You can extract method:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}


I would implement a null safe comparator. There may be an implementation out there, but this is so straightforward to implement that I've always rolled my own.

Note: Your comparator above, if both names are null, won't even compare the value fields. I don't think this is what you want.

I would implement this with something like the following:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

EDIT: Fixed typos in code sample. That's what I get for not testing it first!

EDIT: Promoted nullSafeStringComparator to static.


You could design your class to be immutable (Effective Java 2nd Ed. has a great section on this, Item 15: Minimize mutability) and make sure upon construction that no nulls are possible (and use the null object pattern if needed). Then you can skip all those checks and safely assume the values are not null.


See the bottom of this answer for updated (2013) solution using Guava.


This is what I ultimately went with. It turned out we already had a utility method for null-safe String comparison, so the simplest solution was to make use of that. (It's a big codebase; easy to miss this kind of thing :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

This is how the helper is defined (it's overloaded so that you can also define whether nulls come first or last, if you want):

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

So this is essentially the same as Eddie's answer (although I wouldn't call a static helper method a comparator) and that of uzhin too.

Anyway, in general, I would have strongly favoured Patrick's solution, as I think it's a good practice to use established libraries whenever possible. (Know and use the libraries as Josh Bloch says.) But in this case that would not have yielded the cleanest, simplest code.

Edit (2009): Apache Commons Collections version

Actually, here's a way to make the solution based on Apache Commons NullComparator simpler. Combine it with the case-insensitive Comparator provided in String class:

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

Now this is pretty elegant, I think. (Just one small issue remains: the Commons NullComparator doesn't support generics, so there's an unchecked assignment.)

Update (2013): Guava version

Nearly 5 years later, here's how I'd tackle my original question. If coding in Java, I would (of course) be using Guava. (And quite certainly not Apache Commons.)

Put this constant somewhere, e.g. in "StringUtils" class:

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

Then, in public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

Of course, this is nearly identical to the Apache Commons version (both use JDK's CASE_INSENSITIVE_ORDER), the use of nullsLast() being the only Guava-specific thing. This version is preferable simply because Guava is preferable, as a dependency, to Commons Collections. (As everyone agrees.)

If you were wondering about Ordering, note that it implements Comparator. It's pretty handy especially for more complex sorting needs, allowing you for example to chain several Orderings using compound(). Read Ordering Explained for more!


Another Apache ObjectUtils example. Able to sort other types of objects.

@Override
public int compare(Object o1, Object o2) {
    String s1 = ObjectUtils.toString(o1);
    String s2 = ObjectUtils.toString(o2);
    return s1.toLowerCase().compareTo(s2.toLowerCase());
}

For the specific case where you know the data will not have nulls (always a good idea for strings) and the data is really large, you are still doing three comparisons before actually comparing the values, if you know for sure this is your case, you can optimize a tad bit. YMMV as readable code trumps minor optimization:

        if(o1.name != null && o2.name != null){
            return o1.name.compareToIgnoreCase(o2.name);
        }
        // at least one is null
        return (o1.name == o2.name) ? 0 : (o1.name != null ? 1 : -1);

we can use java 8 to do a null-friendly comparasion between object. supposed i hava a Boy class with 2 fields: String name and Integer age and i want to first compare names and then ages if both are equal.

static void test2() {
    List<Boy> list = new ArrayList<>();
    list.add(new Boy("Peter", null));
    list.add(new Boy("Tom", 24));
    list.add(new Boy("Peter", 20));
    list.add(new Boy("Peter", 23));
    list.add(new Boy("Peter", 18));
    list.add(new Boy(null, 19));
    list.add(new Boy(null, 12));
    list.add(new Boy(null, 24));
    list.add(new Boy("Peter", null));
    list.add(new Boy(null, 21));
    list.add(new Boy("John", 30));

    List<Boy> list2 = list.stream()
            .sorted(comparing(Boy::getName, 
                        nullsLast(naturalOrder()))
                   .thenComparing(Boy::getAge, 
                        nullsLast(naturalOrder())))
            .collect(toList());
    list2.stream().forEach(System.out::println);

}

private static class Boy {
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Boy(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name: " + name + " age: " + age;
    }
}

and the result:

    name: John age: 30
    name: Peter age: 18
    name: Peter age: 20
    name: Peter age: 23
    name: Peter age: null
    name: Peter age: null
    name: Tom age: 24
    name: null age: 12
    name: null age: 19
    name: null age: 21
    name: null age: 24

See the bottom of this answer for updated (2013) solution using Guava.


This is what I ultimately went with. It turned out we already had a utility method for null-safe String comparison, so the simplest solution was to make use of that. (It's a big codebase; easy to miss this kind of thing :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

This is how the helper is defined (it's overloaded so that you can also define whether nulls come first or last, if you want):

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

So this is essentially the same as Eddie's answer (although I wouldn't call a static helper method a comparator) and that of uzhin too.

Anyway, in general, I would have strongly favoured Patrick's solution, as I think it's a good practice to use established libraries whenever possible. (Know and use the libraries as Josh Bloch says.) But in this case that would not have yielded the cleanest, simplest code.

Edit (2009): Apache Commons Collections version

Actually, here's a way to make the solution based on Apache Commons NullComparator simpler. Combine it with the case-insensitive Comparator provided in String class:

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

Now this is pretty elegant, I think. (Just one small issue remains: the Commons NullComparator doesn't support generics, so there's an unchecked assignment.)

Update (2013): Guava version

Nearly 5 years later, here's how I'd tackle my original question. If coding in Java, I would (of course) be using Guava. (And quite certainly not Apache Commons.)

Put this constant somewhere, e.g. in "StringUtils" class:

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

Then, in public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

Of course, this is nearly identical to the Apache Commons version (both use JDK's CASE_INSENSITIVE_ORDER), the use of nullsLast() being the only Guava-specific thing. This version is preferable simply because Guava is preferable, as a dependency, to Commons Collections. (As everyone agrees.)

If you were wondering about Ordering, note that it implements Comparator. It's pretty handy especially for more complex sorting needs, allowing you for example to chain several Orderings using compound(). Read Ordering Explained for more!


In case anyone using Spring, there is a class org.springframework.util.comparator.NullSafeComparator that does this for you as well. Just decorate your own comparable with it like this

new NullSafeComparator<YourObject>(new YourComparable(), true)

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/comparator/NullSafeComparator.html


I would implement a null safe comparator. There may be an implementation out there, but this is so straightforward to implement that I've always rolled my own.

Note: Your comparator above, if both names are null, won't even compare the value fields. I don't think this is what you want.

I would implement this with something like the following:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

EDIT: Fixed typos in code sample. That's what I get for not testing it first!

EDIT: Promoted nullSafeStringComparator to static.


See the bottom of this answer for updated (2013) solution using Guava.


This is what I ultimately went with. It turned out we already had a utility method for null-safe String comparison, so the simplest solution was to make use of that. (It's a big codebase; easy to miss this kind of thing :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

This is how the helper is defined (it's overloaded so that you can also define whether nulls come first or last, if you want):

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

So this is essentially the same as Eddie's answer (although I wouldn't call a static helper method a comparator) and that of uzhin too.

Anyway, in general, I would have strongly favoured Patrick's solution, as I think it's a good practice to use established libraries whenever possible. (Know and use the libraries as Josh Bloch says.) But in this case that would not have yielded the cleanest, simplest code.

Edit (2009): Apache Commons Collections version

Actually, here's a way to make the solution based on Apache Commons NullComparator simpler. Combine it with the case-insensitive Comparator provided in String class:

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

Now this is pretty elegant, I think. (Just one small issue remains: the Commons NullComparator doesn't support generics, so there's an unchecked assignment.)

Update (2013): Guava version

Nearly 5 years later, here's how I'd tackle my original question. If coding in Java, I would (of course) be using Guava. (And quite certainly not Apache Commons.)

Put this constant somewhere, e.g. in "StringUtils" class:

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

Then, in public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

Of course, this is nearly identical to the Apache Commons version (both use JDK's CASE_INSENSITIVE_ORDER), the use of nullsLast() being the only Guava-specific thing. This version is preferable simply because Guava is preferable, as a dependency, to Commons Collections. (As everyone agrees.)

If you were wondering about Ordering, note that it implements Comparator. It's pretty handy especially for more complex sorting needs, allowing you for example to chain several Orderings using compound(). Read Ordering Explained for more!


I was looking for something similar and this seemed a bit complicated so I did this. I think it's a little easier to understand. You can use it as a Comparator or as a one liner. For this question you would change to compareToIgnoreCase(). As is, nulls float up. You can flip the 1, -1 if you want them to sink.

StringUtil.NULL_SAFE_COMPARATOR.compare(getName(), o.getName());

.

public class StringUtil {
    public static final Comparator<String> NULL_SAFE_COMPARATOR = new Comparator<String>() {

        @Override
        public int compare(final String s1, final String s2) {
            if (s1 == s2) {
                //Nulls or exact equality
                return 0;
            } else if (s1 == null) {
                //s1 null and s2 not null, so s1 less
                return -1;
            } else if (s2 == null) {
                //s2 null and s1 not null, so s1 greater
                return 1;
            } else {
                return s1.compareTo(s2);
            }
        }
    }; 

    public static void main(String args[]) {
        final ArrayList<String> list = new ArrayList<String>(Arrays.asList(new String[]{"qad", "bad", "sad", null, "had"}));
        Collections.sort(list, NULL_SAFE_COMPARATOR);

        System.out.println(list);
    }
}

You could design your class to be immutable (Effective Java 2nd Ed. has a great section on this, Item 15: Minimize mutability) and make sure upon construction that no nulls are possible (and use the null object pattern if needed). Then you can skip all those checks and safely assume the values are not null.


This is my implementation that I use to sort my ArrayList. the null classes are sorted to the last.

for my case, EntityPhone extends EntityAbstract and my container is List < EntityAbstract>.

the "compareIfNull()" method is used for null safe sorting. The other methods are for completeness, showing how compareIfNull can be used.

@Nullable
private static Integer compareIfNull(EntityPhone ep1, EntityPhone ep2) {

    if (ep1 == null || ep2 == null) {
        if (ep1 == ep2) {
            return 0;
        }
        return ep1 == null ? -1 : 1;
    }
    return null;
}

private static final Comparator<EntityAbstract> AbsComparatorByName = = new Comparator<EntityAbstract>() {
    @Override
    public int compare(EntityAbstract ea1, EntityAbstract ea2) {

    //sort type Phone first.
    EntityPhone ep1 = getEntityPhone(ea1);
    EntityPhone ep2 = getEntityPhone(ea2);

    //null compare
    Integer x = compareIfNull(ep1, ep2);
    if (x != null) return x;

    String name1 = ep1.getName().toUpperCase();
    String name2 = ep2.getName().toUpperCase();

    return name1.compareTo(name2);
}
}


private static EntityPhone getEntityPhone(EntityAbstract ea) { 
    return (ea != null && ea.getClass() == EntityPhone.class) ?
            (EntityPhone) ea : null;
}

In case anyone using Spring, there is a class org.springframework.util.comparator.NullSafeComparator that does this for you as well. Just decorate your own comparable with it like this

new NullSafeComparator<YourObject>(new YourComparable(), true)

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/comparator/NullSafeComparator.html


I would implement a null safe comparator. There may be an implementation out there, but this is so straightforward to implement that I've always rolled my own.

Note: Your comparator above, if both names are null, won't even compare the value fields. I don't think this is what you want.

I would implement this with something like the following:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

EDIT: Fixed typos in code sample. That's what I get for not testing it first!

EDIT: Promoted nullSafeStringComparator to static.


One of the simple way of using NullSafe Comparator is to use Spring implementation of it, below is one of the simple example to refer :

public int compare(Object o1, Object o2) {
        ValidationMessage m1 = (ValidationMessage) o1;
        ValidationMessage m2 = (ValidationMessage) o2;
        int c;
        if (m1.getTimestamp() == m2.getTimestamp()) {
            c = NullSafeComparator.NULLS_HIGH.compare(m1.getProperty(), m2.getProperty());
            if (c == 0) {
                c = m1.getSeverity().compareTo(m2.getSeverity());
                if (c == 0) {
                    c = m1.getMessage().compareTo(m2.getMessage());
                }
            }
        }
        else {
            c = (m1.getTimestamp() > m2.getTimestamp()) ? -1 : 1;
        }
        return c;
    }

This is my implementation that I use to sort my ArrayList. the null classes are sorted to the last.

for my case, EntityPhone extends EntityAbstract and my container is List < EntityAbstract>.

the "compareIfNull()" method is used for null safe sorting. The other methods are for completeness, showing how compareIfNull can be used.

@Nullable
private static Integer compareIfNull(EntityPhone ep1, EntityPhone ep2) {

    if (ep1 == null || ep2 == null) {
        if (ep1 == ep2) {
            return 0;
        }
        return ep1 == null ? -1 : 1;
    }
    return null;
}

private static final Comparator<EntityAbstract> AbsComparatorByName = = new Comparator<EntityAbstract>() {
    @Override
    public int compare(EntityAbstract ea1, EntityAbstract ea2) {

    //sort type Phone first.
    EntityPhone ep1 = getEntityPhone(ea1);
    EntityPhone ep2 = getEntityPhone(ea2);

    //null compare
    Integer x = compareIfNull(ep1, ep2);
    if (x != null) return x;

    String name1 = ep1.getName().toUpperCase();
    String name2 = ep2.getName().toUpperCase();

    return name1.compareTo(name2);
}
}


private static EntityPhone getEntityPhone(EntityAbstract ea) { 
    return (ea != null && ea.getClass() == EntityPhone.class) ?
            (EntityPhone) ea : null;
}

Another Apache ObjectUtils example. Able to sort other types of objects.

@Override
public int compare(Object o1, Object o2) {
    String s1 = ObjectUtils.toString(o1);
    String s2 = ObjectUtils.toString(o2);
    return s1.toLowerCase().compareTo(s2.toLowerCase());
}

You can extract method:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}


I always recommend using Apache commons since it will most likely be better than one you can write on your own. Plus you can then do 'real' work rather then reinventing.

The class you are interested in is the Null Comparator. It allows you to make nulls high or low. You also give it your own comparator to use when the two values are not null.

In your case you can have a static member variable that does the comparison and then your compareTo method just references that.

Somthing like

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}

Even if you decide to roll your own, keep this class in mind since it is very useful when ordering lists thatcontain null elements.


You can extract method:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}


You could design your class to be immutable (Effective Java 2nd Ed. has a great section on this, Item 15: Minimize mutability) and make sure upon construction that no nulls are possible (and use the null object pattern if needed). Then you can skip all those checks and safely assume the values are not null.


You can extract method:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}


I always recommend using Apache commons since it will most likely be better than one you can write on your own. Plus you can then do 'real' work rather then reinventing.

The class you are interested in is the Null Comparator. It allows you to make nulls high or low. You also give it your own comparator to use when the two values are not null.

In your case you can have a static member variable that does the comparison and then your compareTo method just references that.

Somthing like

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}

Even if you decide to roll your own, keep this class in mind since it is very useful when ordering lists thatcontain null elements.


One of the simple way of using NullSafe Comparator is to use Spring implementation of it, below is one of the simple example to refer :

public int compare(Object o1, Object o2) {
        ValidationMessage m1 = (ValidationMessage) o1;
        ValidationMessage m2 = (ValidationMessage) o2;
        int c;
        if (m1.getTimestamp() == m2.getTimestamp()) {
            c = NullSafeComparator.NULLS_HIGH.compare(m1.getProperty(), m2.getProperty());
            if (c == 0) {
                c = m1.getSeverity().compareTo(m2.getSeverity());
                if (c == 0) {
                    c = m1.getMessage().compareTo(m2.getMessage());
                }
            }
        }
        else {
            c = (m1.getTimestamp() > m2.getTimestamp()) ? -1 : 1;
        }
        return c;
    }

we can use java 8 to do a null-friendly comparasion between object. supposed i hava a Boy class with 2 fields: String name and Integer age and i want to first compare names and then ages if both are equal.

static void test2() {
    List<Boy> list = new ArrayList<>();
    list.add(new Boy("Peter", null));
    list.add(new Boy("Tom", 24));
    list.add(new Boy("Peter", 20));
    list.add(new Boy("Peter", 23));
    list.add(new Boy("Peter", 18));
    list.add(new Boy(null, 19));
    list.add(new Boy(null, 12));
    list.add(new Boy(null, 24));
    list.add(new Boy("Peter", null));
    list.add(new Boy(null, 21));
    list.add(new Boy("John", 30));

    List<Boy> list2 = list.stream()
            .sorted(comparing(Boy::getName, 
                        nullsLast(naturalOrder()))
                   .thenComparing(Boy::getAge, 
                        nullsLast(naturalOrder())))
            .collect(toList());
    list2.stream().forEach(System.out::println);

}

private static class Boy {
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Boy(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name: " + name + " age: " + age;
    }
}

and the result:

    name: John age: 30
    name: Peter age: 18
    name: Peter age: 20
    name: Peter age: 23
    name: Peter age: null
    name: Peter age: null
    name: Tom age: 24
    name: null age: 12
    name: null age: 19
    name: null age: 21
    name: null age: 24

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Comparator;

public class TestClass {

    public static void main(String[] args) {

        Student s1 = new Student("1","Nikhil");
        Student s2 = new Student("1","*");
        Student s3 = new Student("1",null);
        Student s11 = new Student("2","Nikhil");
        Student s12 = new Student("2","*");
        Student s13 = new Student("2",null);
        List<Student> list = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s11);
        list.add(s12);
        list.add(s13);

        list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder())));

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }


    }

}

output is

Student [name=*, id=1]
Student [name=*, id=2]
Student [name=Nikhil, id=1]
Student [name=Nikhil, id=2]
Student [name=null, id=1]
Student [name=null, id=2]

For the specific case where you know the data will not have nulls (always a good idea for strings) and the data is really large, you are still doing three comparisons before actually comparing the values, if you know for sure this is your case, you can optimize a tad bit. YMMV as readable code trumps minor optimization:

        if(o1.name != null && o2.name != null){
            return o1.name.compareToIgnoreCase(o2.name);
        }
        // at least one is null
        return (o1.name == o2.name) ? 0 : (o1.name != null ? 1 : -1);

I would implement a null safe comparator. There may be an implementation out there, but this is so straightforward to implement that I've always rolled my own.

Note: Your comparator above, if both names are null, won't even compare the value fields. I don't think this is what you want.

I would implement this with something like the following:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

EDIT: Fixed typos in code sample. That's what I get for not testing it first!

EDIT: Promoted nullSafeStringComparator to static.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to refactoring

Find and replace Android studio How to change a package name in Eclipse? How do I deal with "signed/unsigned mismatch" warnings (C4018)? How to use IntelliJ IDEA to find all unused code? What are some alternatives to ReSharper? Replace Multiple String Elements in C# Python: avoiding pylint warnings about too many arguments Detecting superfluous #includes in C/C++? How to simplify a null-safe compareTo() implementation? Find unused code

Examples related to comparison

Wildcard string comparison in Javascript How to compare two JSON objects with the same elements in a different order equal? Comparing strings, c++ Char Comparison in C bash string compare to multiple correct values Comparing two hashmaps for equal values and same key sets? Comparing boxed Long values 127 and 128 Compare two files report difference in python How do I fix this "TypeError: 'str' object is not callable" error? Compare cell contents against string in Excel

Examples related to null

getElementById in React Filter values only if not null using lambda in Java8 Why use Optional.of over Optional.ofNullable? How to resolve TypeError: Cannot convert undefined or null to object Check if returned value is not null and if so assign it, in one line, with one method call How do I assign a null value to a variable in PowerShell? Using COALESCE to handle NULL values in PostgreSQL How to check a Long for null in java Check if AJAX response data is empty/blank/null/undefined/0 Best way to check for "empty or null value"

Examples related to compareto

How do I write a compareTo method which compares objects? compareTo with primitives -> Integer / int BigDecimal equals() versus compareTo() compareTo() vs. equals() How to simplify a null-safe compareTo() implementation?