Natural order comparators in Java
This post will discuss natural order comparators provided by JDK and write our own natural order comparators in Java. We will also see how to handle null values in a Collection or array.
Comparators are the comparison functions that can be applied to collections of objects or an array to impose a total ordering. They can be passed to Collections.sort() or Arrays.sort() to allow precise control over the sort order. We can also use them to provide an ordering for collections of objects that don’t have a natural ordering.
Let’s discuss various natural order comparators provided by JDK that compares objects in the natural order:
1. Using Comparator.naturalOrder() method
We can use static Comparator.naturalOrder() that returns a comparator that compares objects in the natural order.
Usage:
|
1 2 3 |
String[] s = { "B", "C", "A" }; Arrays.sort(s, Comparator.naturalOrder()); System.out.println(Arrays.toString(s)); // [A, B, C] |
The above code will throw a NullPointerException if the specified array contains any null value. Java provides two methods to handle nulls:
1. Using nullsFirst()
Comparator‘s nullsFirst() method takes another comparator and returns a comparator that considers null to be less than non-null values. If passed to a sort method, the comparator will put all null values before all non-null values and apply natural ordering to all non-null elements, as shown below:
|
1 2 3 |
String[] s = { "B", null, "C", "A", null }; Arrays.sort(s, Comparator.nullsFirst(Comparator.naturalOrder())); System.out.println(Arrays.toString(s)); // [null, null, A, B, C] |
If the specified comparator is null, then the returned comparator considers all non-null values equal, i.e., non-null values will remain unsorted a shown below.
|
1 2 3 |
String[] s = { "B", null, "C", "A", null }; Arrays.sort(s, Comparator.nullsFirst(null)); System.out.println(Arrays.toString(s)); // [null, null, B, C, A] |
2. Using nullsLast()
Comparator‘s nullsLast() method takes another comparator and returns a comparator that considers null to be greater than non-null values. If passed to a sort method, the comparator will put all null values after all non-null values and apply natural ordering to all non-null elements, as shown below:
|
1 2 3 |
String[] s = { "B", null, "C", "A", null }; Arrays.sort(s, Comparator.nullsLast(Comparator.naturalOrder())); System.out.println(Arrays.toString(s)); // [A, B, C, null, null] |
If the specified comparator is null, then the returned comparator considers all non-null values to be equal, i.e., non-null values will remain unsorted:
|
1 2 3 |
String[] s = { "B", null, "C", "A", null }; Arrays.sort(s, Comparator.nullsLast(null)); System.out.println(Arrays.toString(s)); // [B, C, A, null, null] |
2. Using Custom Comparators
We can also write our own custom natural order comparators:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import java.util.Arrays; import java.util.Comparator; class Main { public static void main(String[] args) { String[] s = { "B", "C", "A" }; Arrays.sort(s, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); System.out.println(Arrays.toString(s)); } } |
Output:
[A, B, C]
We can convert the above code to use generics:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.util.Arrays; import java.util.Comparator; class CustomComparator<T extends Comparable<T>> implements Comparator<T> { @Override public int compare(T a, T b) { return a.compareTo(b); } } class Main { public static void main(String[] args) { String[] s = { "B", "C", "A" }; Arrays.sort(s, new CustomComparator()); System.out.println(Arrays.toString(s)); } } |
Output:
[A, B, C]
We can also replace the comparator with lambda expressions (in Java 8 and above):
|
1 2 3 |
String[] s = { "B", "C", "A" }; Arrays.sort(s, (a, b) -> a.compareTo(b)); System.out.println(Arrays.toString(s)); |
How can we handle nulls?
Like Comparator.naturalOrder(), the above code will throw a NullPointerException if the specified array contains any null value. We can easily modify the compare() method to handle nulls, as shown below:
1. To return a comparator that considers null to be less than non-null values:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class CustomComparator<T extends Comparable<T>> implements Comparator<T> { @Override public int compare(T a, T b) { // return 0 if both `a` and `b` are null if (a == null && b == null) { return 0; } // return -1 if `a` is null and `b` is not null if (a == null) { return -1; } // return 1 if `b` is null and `a` is not null if (b == null) { return 1; } // if both `a` and `b` are not null return a.compareTo(b); } } |
2. To return a comparator that considers null to be greater than non-null values:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class CustomComparator<T extends Comparable<T>> implements Comparator<T> { @Override public int compare(T a, T b) { // return 0 if both `a` and `b` are null if (a == null && b == null) { return 0; } // return 1 if `a` is null and `b` is not null if (a == null) { return 1; } // return -1 if `b` is null and `a` is not null if (b == null) { return -1; } // if both `a` and `b` are not null return a.compareTo(b); } } |
3. Using Comparator.comparing() method
Java 8 has brought several enhancements to the Comparator interface, such as introducing a new static method comparing(). We can pass an instance method reference to the Comparator.comparing() method, and it will extract and returns a comparator based on that function.
Usage:
|
1 2 3 4 5 6 7 |
String[] s = { "B", "C", "A" }; // using method reference Arrays.sort(s, Comparator.comparing(Function.identity())); // [A, B, C] System.out.println(Arrays.toString(s)); |
We can also replace the identity method by the corresponding lambda expression:
|
1 |
Arrays.sort(s, Comparator.comparing(i -> i)); |
This method also throws a NullPointerException if the specified array contains any null value. As seen in the previous sections, we can use nullsFirst() or nullsLast() to handle null values:
|
1 |
Arrays.sort(s, Comparator.nullsFirst(Comparator.comparing(Function.identity()))); |
|
1 |
Arrays.sort(s, Comparator.nullsLast(Comparator.comparing(Function.identity()))); |
4. Using Guava Library
Google’s Guava library provides static Ordering.natural() that returns an Ordering that uses the natural order of the values.
5. Using Apache Commons Collections
Apache commons-collections provides static ComparatorUtils.naturalComparator() that returns a natural order comparator.
Natural Order Comparators by Apache Commons Collections in Java
That’s all about natural order comparators in Java.
Related Article:
Reference: Comparator (Java Platform SE 8 )
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)