Sorting a List having null values with Comparator's nullsFirst

Hello Friends,

In this tutorial, we will see how we can sort a list of items when few of the items are null in the list using Java 8 Comparator.nullsFirst, such that nulls are treated as smallest elements in the list.

- What is Comparator
- What is nullsFirst method doing in Comparator
- Sorting a list of Strings having non null names
- Sorting a list of Strings having names and Nulls without using nullsFirst
- Solving above problem by sorting the list using nullsFirst method
- Sorting a list of Custom objects without nulls
- Sorting a list of Custom objects with nulls without using nullsFirst
- Solving above problem by sorting the list using nullsFirst method
- Sorting the list having employee with name as null


What is a Comparator? 

Comparator is a FunctionalInterface which has following abstract method

int compare(T o1, T o2);

So if you want to sort ,say your list.You can create a class implementing Comparator interface's compare method, wherein you can define the logic of sorting and pass this comparator to the list.sort() method and it will then sort according to your defined logic.

Alternatively, rather than creating a separate class implementing Comparator interface, you can pass lambda function(implementing compare method of Comparator) to list.sort() method.

What is nullsFirst method doing in Comparator?

In Java 8, there has been addition of lots of default and static methods in Comparator interface.

nullsFirst is one of the static method defined in the Comparator interface having following signature:

public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
So what does it do ?

- Returns a null-friendly comparator that considers null to be less than non null.
- When both objects are null, they are considered equal.
- When both are non null, the specified comparator, which is passed to nullsFirst method as parameter, is used to determined the sort order
- When the specified comparator is null, then the returned comparator consider all non null values to be equal.

To understand the usage of nullsFirst , let us try to sort a list of Strings having name of employees ,

-  First without null values  
-  Then with null values but without nullsFirst
-  Then with null values and with nullsFirst 
-  Then we will do same above steps for a custom Employee object  
-   And then we will see what if one of the property on the basis of which sorting needs to be done, is null in a custom object :

Sorting a list of Strings having non null names 

package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.List;
import java.util.Comparator;

public class ComparatorTestWithListOfNamesWithoutNulls {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Gaurav", "Tendulkar", "Suresh", "Rohit", "Bumrah");
        System.out.println("Before Sorting:");
        names.forEach(System.out::println);
        names.sort(Comparator.naturalOrder());
        System.out.println("After Sorting:");
        names.forEach(System.out::println);
    }
}

Before Sorting:

Gaurav
Tendulkar
Suresh
Rohit
Bumrah

After Sorting:
Bumrah
Gaurav
Rohit
Suresh
Tendulkar

Sorting a list of Strings having names and nulls without using nullsFirst

package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class ComparatorTestWithListOfNamesAndNulls {
  public static void main(String[] args) { 
     List<String> names  = Arrays.asList("Gaurav", null, "Sachin", "Suresh",null, "Rohit", "Jasprit", null);
     System.out.println("Before Sorting:");
     names.forEach(System.out ::println);
     names.sort(Comparator.naturalOrder());
     System.out.println("After Sorting:");
     names.forEach(System.out ::println);
  }
}

Before Sorting:
Gaurav
null
Sachin
Suresh
null
Rohit
Jasprit
null
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:52)
at java.base/java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47)
at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.base/java.util.TimSort.sort(TimSort.java:220)
at java.base/java.util.Arrays.sort(Arrays.java:1442)
at java.base/java.util.Arrays$ArrayList.sort(Arrays.java:4426)
at com.blogspot.javasolutionsguide.ComparatorTestWithListOfNamesAndNulls.main(ComparatorTestWithListOfNamesAndNulls.java:12)

As we can see because ,NaturalOrderComparator's compare method tries to compare two o objects by invoking compareTo on one of the object, we get NullPointerException.

Solving above problem by sorting the list using nullsFirst method

package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.List;
import java.util.Comparator;

public class ComparatorTestWithNullsFirstForListOfNames {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Gaurav", null, "Tendulkar", "Suresh", null, "Rohit", "Jasprit", null);
        System.out.println("Before Sorting:");
        names.forEach(System.out::println);
        names.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
        System.out.println("After Sorting:");
        names.forEach(System.out::println);
    }
}

Before Sorting:

Gaurav
null
Tendulkar
Suresh
null
Rohit
Jasprit
null

After Sorting:
null
null
null
Gaurav
Jasprit
Rohit
Suresh
Tendulkar

Sorting a list of custom objects without nulls

We will create an Employee class, which will be a simple POJO as below : 
package com.blogspot.javasolutionsguide;

public class Employee {

    private int id;
    private String name;
    private String department;

    public Employee(int id, String name, String department) {
        super();
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getDepartment() {
        return department;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", department=" + department + "]";
    }
}
And here is our test class :
package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class ComparatorTestWithListOfEmployeesWithoutNulls {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(new Employee(1, "Gaurav", "IT"),
                new Employee(2, "Tendulkar", "Admin"),
                new Employee(3, "Suresh", "IT"),
                new Employee(4, "Rohit", "Admin"),
                new Employee(5, "Bumrah", "Admin"));
        System.out.println("Before Sorting:");
        employees.forEach(System.out::println);
        System.out.println("After Sorting:");
        employees.sort(Comparator.comparing(Employee::getName));
        employees.forEach(System.out::println);
    }
}

Before Sorting:
Employee [id=1, name=Gaurav, department=IT]
Employee [id=2, name=Tendulkar, department=Admin]
Employee [id=3, name=Suresh, department=IT]
Employee [id=4, name=Rohit, department=Admin]
Employee [id=5, name=Bumrah, department=Admin]

After Sorting:

Employee [id=5, name=Bumrah, department=Admin]
Employee [id=1, name=Gaurav, department=IT]
Employee [id=4, name=Rohit, department=Admin]
Employee [id=3, name=Suresh, department=IT]
Employee [id=2, name=Tendulkar, department=Admin]

Sorting a list of custom objects with nulls without using nullsFirst

package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class ComparatorTestWithListOfEmployeesWithNulls {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(new Employee(1, "Gaurav", "IT"),
                null,
                new Employee(2, "Tendulkar", "Admin"),
                new Employee(3, "Suresh", "IT"),
                null,
                new Employee(4, "Rohit", "Admin"),
                new Employee(5, "Bumrah", "Admin"),
                null);

        employees.sort(Comparator.comparing(Employee::getName));
        employees.forEach(System.out::println);
    }
}

Before Sorting:
Employee [id=1, name=Gaurav, department=IT]
null
Employee [id=2, name=Tendulkar, department=Admin]
Employee [id=3, name=Suresh, department=IT]
null
Employee [id=4, name=Rohit, department=Admin]
Employee [id=5, name=Bumrah, department=Admin]
null
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.base/java.util.TimSort.sort(TimSort.java:220)
at java.base/java.util.Arrays.sort(Arrays.java:1442)
at java.base/java.util.Arrays$ArrayList.sort(Arrays.java:4426)
at com.blogspot.javasolutionsguide.ComparatorTestWithListOfEmployeesWithNulls.main(ComparatorTestWithListOfEmployeesWithNulls.java:19)

Solving above problem by sorting the list using nullsFirst method 

package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ComparatorTestWithListOfEmployeesWithNullsAndNullsFirst {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(new Employee(1, "Gaurav", "IT"),
                null,
                new Employee(2, "Tendulkar", "Admin"),
                new Employee(3, "Suresh", "IT"),
                null,
                new Employee(4, "Rohit", "Admin"),
                new Employee(5, "Bumrah", "Admin"),
                null);
        Collections.sort(employees, Comparator.nullsFirst((emp1, emp2) -> emp1.getName().compareToIgnoreCase(emp2.getName())));
        employees.forEach(System.out::println);
    }
}
null
null
null
Employee [id=5, name=Bumrah, department=Admin]
Employee [id=1, name=Gaurav, department=IT]
Employee [id=4, name=Rohit, department=Admin]
Employee [id=3, name=Suresh, department=IT]
Employee [id=2, name=Tendulkar, department=Admin]

Sorting the list having employee with name as null

package com.blogspot.javasolutionsguide;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class ComparatorTestWithListOfEmployeesWithNullNamesAndNullsFirst {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(new Employee(1, "Gaurav", "IT"),
                new Employee(2, "Tendulkar", "Admin"),
                new Employee(3, null, "IT"),
                new Employee(4, "Rohit", "Admin"),
                new Employee(5, "Bumrah", "Admin"));
        System.out.println("Before Sorting:");
        employees.forEach(System.out ::println);
        employees.sort(Comparator.comparing(Employee::getName,Comparator.nullsFirst(Comparator.naturalOrder())));
        System.out.println("After Sorting:");
        employees.forEach(System.out::println);
    }
}

Before Sorting:
Employee [id=1, name=Gaurav, department=IT]
Employee [id=2, name=Tendulkar, department=Admin]
Employee [id=3, name=null, department=IT]
Employee [id=4, name=Rohit, department=Admin]
Employee [id=5, name=Bumrah, department=Admin]

After Sorting:
Employee [id=3, name=null, department=IT]
Employee [id=5, name=Bumrah, department=Admin]
Employee [id=1, name=Gaurav, department=IT]
Employee [id=4, name=Rohit, department=Admin]
Employee [id=2, name=Tendulkar, department=Admin]

Summary

When we have list of elements where few elements are null and we want these nulls to be treated as the smallest in the list, we can use nullsFirst method of Comparator interface, which does following :
- Returns a null-friendly comparator that considers null to be less than non null.
- When both objects are null, they are considered equal.
- When both are non null, the specified comparator, which is passed to nullsFirst method as parameter, is used to determined the sort order
- When the specified comparator is null, then the returned comparator consider all non null values to be equal.

Thanks for reading. If you liked the post, you can share it and can subscribe to this blog for more such posts.