Java 8 has added lots of good to use methods to make it easy to use with streams, easy to handle nulls, chain comparators, reverse order etc. We will take simple example to understand new improvements to Comparator in Java 8.
Example:
- Create comparator for Person class which has two attributes & getter/setters – name & age
- Comparator should handle null values and treat null as last in sorting.
- Comparator should first compare based on name in ascending order.
- If names are same, then it should compare based on age.
Before Java 8:
Before Java 8, comparator will look something like below which satisfied all conditions above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class PersonComparatorOld implements Comparator<Person> { @Override public int compare(Person p1, Person p2) { // Null Handling so that nulls go last in sorting. if (p1 == null) return 1; if (p2 == null) return -1; if (p1.getName().equals(p2.getName())) { // Compare based on age,if names are same. return p1.getAge().compareTo(p2.getAge()); } else { // Compare based on names, if names are different. return p1.getName().compareToIgnoreCase(p2.getName()); } } } |
Test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.Arrays; import java.util.Comparator; public class ComparatorRevisited { public static void main(String[] args) { Person[] persons = { new Person("Ron", 25), new Person("John", 30), new Person("Andy", 23), new Person("John", 27), null }; Arrays.sort(persons, new PersonComparatorOld()); System.out.println("Sorted = " + Arrays.toString(persons)); } } |
Output:
1 |
Sorted = [Andy(23), John(27), John(30), Ron(25), null] |
With Java 8 improvements:
Well with Java 8, we don’t even need to prepare separate comparator implementation class to achieve above requierments.
- Comparator.nullsLast – This wraps a comparator & handles null in a way so that null treated as last in sorting order. There is also another variant Comparator.nullsFirst which does opposite.
- Comparator.comparing – Takes getter function for the value on which comparison should happen. Return type should be Comparable
- Comparator.thenComparing – If earlier comparator marks objects as equal, then this comparator will be applied.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import static java.util.Comparator.comparing; import static java.util.Comparator.nullsLast; import java.util.Arrays; import java.util.Comparator; public class ComparatorRevisited { public static void main(String[] args) { Person[] persons = { new Person("Ron", 25), new Person("John", 30), new Person("Andy", 23), new Person("John", 27), null }; Arrays.sort(persons, nullsLast(comparing(Person::getName).thenComparing(Person::getAge))); System.out.println("Sorted = " + Arrays.toString(persons)); } } |
Output:
1 |
Sorted = [Andy(23), John(27), John(30), Ron(25), null] |
Easy Reversal: Its also very easy to reverse the order just using Comparator.reversed()
1 2 3 |
Arrays.sort(persons, nullsLast( comparing(Person::getName).thenComparing(Person::getAge)) .reversed()); |
Output:
1 |
Sorted = [null, Ron(25), John(30), John(27), Andy(23)] |
Easy to use with streams: This also makes it very easy to use with Java streams as shown in below example.
1 2 |
Arrays.stream(persons).sorted(nullsLast(comparing(Person::getName).thenComparing(Person::getAge))) .forEach(System.out::println); |
Output:
1 2 3 4 5 |
Andy(23) John(27) John(30) Ron(25) null |