Wednesday, May 24, 2023

Java 8 Comparator comparing() and thenComparing() Example - Tutorial

Hello Java programmers, you may know that the JDK 8 has added a lot of new methods into the Comparator interface which makes comparing and sorting objects in Java really easy. Two such methods are called comparing() and thenComparing() which was added in the java.util.Comparator interface. These methods accept a key extractor function and return a Comparator that can compare to that key. The key must be Comparable though like String, Integer, or any Java class which implements java.lang.Comparable interface, I mean the key must implement Comparable interface. 

Both comparing() and thenComparing() allows you to easily compare objects on any field as well as compare them on multiple fields by chaining comparators. As the name suggests, you can use the thenComparing() method to chain comparators to compare objects on multiple fields and multiple orders. 

For example, you can use comparing() and thenComparing() to compare Book objects first on author and then price. you can also choose to sort on increasing order of price of decreasing order of price. 

Overall these new Comparator methods make comparing objects really easy and fun as you can also pass both lambda expression and method reference to this method, making it super easy to write custom Comparators on the fly as shown in the following example but before that let's create a custom Java object or POJO (Plain Old Java object to demonstrate this comparison and sorting example in Java. 

Also, in the past, I have shared Comparator example for custom order sorting and Comparable example for natural order soring, if you are new to Comparator and Comparable interface in Java, you can check those articles to get yourself familiar with Comparator and Comparable in Java as well comparison and sorting of Java objects. 




How to compare objects using Comparator.comparing() and thenComparing() in Java

In order to demonstrate the use of Comparator and Comparable in Java 8, we need a domain object. I like books, so I'll create a Book object with some fields to demonstrate how you can sort a list of books using Java 8 features like lambda expressions and method reference

Here is how our Book object will be like:
public class Book implements Comparable < Book > {
  private String title;
  private String author;
  private int price;

  public Book(String title, String author, int price) {
    this.title = title;
    this.author = author;
    this.price = price;
  }

  public String getTitle() {
    return title;
  }

  public String getAuthor() {
    return author;
  }

  public int getPrice() {
    return price;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public void setAuthor(String author) {
    this.author = author;
  }

  public void setPrice(int price) {
    this.price = price;
  }

  @Override
  public String toString() {
    return "Book [title=" + title + ", author=" + author + ", price=" +
      price + "]";
  }

  // the old way to implement CompareTo method to compare
  // object by multiple fields, you'll learn new way as well
  @Override
  public int compareTo(Book b) {
    int i = this.title.compareTo(b.title);
    if (i != 0) return i;

    i = this.author.compareTo(b.author);
    if (i != 0) return i;

    return Integer.compare(this.price, b.price);
  }

}
and here is the list of Books which we'll sort in this article:

List<Book> listOfBooks = new ArrayList<>();
listOfBooks.add(new Book("Effective Java", "Joshua Bloch", 32));
listOfBooks.add(new Book("Java Puzzlers", "Joshua Bloch", 22));
listOfBooks.add(new Book("Java Concurrency in Practice", 
"Brian Goetz", 42));
listOfBooks.add(new Book("Java SE 8 for Really Impatient",
 "Cay S. Horstmann", 34));
listOfBooks.add(new Book("Core Java", "Cay S. Horstmann",32));
Now, let's see how we can sort this list of objects using new features of Java 8 and new methods added to the Comparator class like the comparing() and thenComparing() methods. 

How to compare objects using comparing() and thenComparing() in Java


Let's first sort the list of books by authors again but this time using Comparator.comparing() method:

listOfBooks.sort(Comparator.comparing((Book b) -> b.getAuthor()));

Since the author is a String, this code will extract the author as key and return a Comparator which can compare objects by author. The result will be the same as in the preceding example as shown below:

listOfBooks.sort(Comparator.comparing((Book b) -> b.getAuthor()));
System.out.println("list of books after sorting 
 using comparing() method: " 
+ listOfBooks);


Output:
list of books after sorting using comparing method: 
[
Book [title=Java Concurrency in Practice, author=Brian Goetz, price=42],
Book [title=Java SE 8 for Really Impatient, author=Cay S. Horstmann,
 price=34], 
Book [title=Core Java, author=Cay S. Horstmann, price=32],
Book [title=Effective Java, author=Joshua Bloch, price=32], 
Book [title=Java Puzzlers, author=Joshua Bloch, price=22]
]

Now, let's see another magic of Java 8, which will make it comparing objects even more readable, reusable, and composable by using method reference instead of a lambda expression with Comparator.comparing() method as shown below:

listOfBooks.sort(Comparator.comparing(Book::getAuthor));

You can see this is much more readable, clean, and concise. You can easily see that we are comparing books based on their author.  You can also use the thenComparing() method to compare objects on multiple fields. For example to compare books first by the author and then on the price you can just chain comparators as given in the following example

listOfBooks.sort(
Comparator.comparing((Book b) -> b.getAuthor())
          .thenComparing((Book b) -> b.getPrice())

Another example of comparing and thenComparing to sort objects on multiple fields

Here is another example of using Comparator. comparing() and thenComparing() methods to compare a Java object into multiple parameters. In this example, we have three comparators, the first comparator compares Student object on firstName, second compare them on both firstName and lastName, and the third comparator compares them on both name and age. For the age field, we have also used a reverse comparator which means they will be compared in reverse order. 

here is a full code example:
import java.util.Comparator;

public class Student {
	private String firstName;
	private String lastName;
	private int age;
	
	Comparator<Student> firstNameComparator 
                   = Comparator.comparing(Student::geFirsttName);	 
	Comparator<Student> fullNameComparator
                   =  Comparator.comparing(Student::geFirsttName)
			        .thenComparing(Student::geLastName);	
	Comparator<Student> nameAndAgeComparator 
                   = Comparator.comparing(Student::geFirsttName)
			       .thenComparing(Student::geFirsttName)
                               .thenComparing(Student::getAge,
                                            Comparator.reverseOrder());
	
}
You can see that we have chained comparators on the second and third examples to compare Student objects on multiple fields. You can chain as many comparators as you want, but code is still ver readable, and comparing logic is obvious.  If your list contains null elements then you can also use the nullsFirst() and nullsLast() methods to put null objects either in the first or last position. 

That's all about how to use comparing() and thenComparing() methods of the Comparator class to compare objects in Java 8. The best thing about this method is that you can pass lambda expression or method interface to this method to compare objects.  

If you want to learn more about advanced comparator methods like thenComparing() then I highly recommend you to check out my post about advanced comparator and comparable examples in Java, where I have shared how to compare objects on multiple fields and different orders in Java, including nulls. 

Other Core Java Articles you may like:
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • 5 Free Courses to learn Java 8 and 9 (courses)
  • How to format/parse the date with LocalDateTime in Java 8? (tutorial)
  • How to use filter() method in Java 8 (tutorial)
  • How to sort the map by keys in Java 8? (example)
  • How to convert List to Map in Java 8 (solution)
  • What is the default method in Java 8? (example)
  • 5 Books to Learn Java 8 from Scratch (books)
  • How to use Stream class in Java 8 (tutorial)
  • Difference between abstract class and interface in Java 8? (answer)
  • How to sort the may by values in Java 8? (example)
  • How to join String in Java 8 (example)
  • 7 Best Collections and Stream Courses for Java developers (courses)
Thanks for reading this article so far if you find this Comparator.comparing() Example in Java for comparing objects in their natural order then, please Share it with your friends and colleagues. If you have any questions or feedback then please drop a note. 

No comments:

Post a Comment