Comparator: Custom Comparison of Data
Let's look at the second functional interface, Comparator, see how it implements comparison, and understand the difference between Comparator and Comparable.
What Is Comparator?
The key method in the Comparator functional interface is:
int compare(T o1, T o2);
The compare(T o1, T o2) method returns:
- A negative number if
o1is less thano2; - Zero if
o1ando2are equal; - A positive number if
o1is greater thano2.
Practical Application
Let's implement sorting of Book objects using the Comparator interface. Instead of implementing the comparison method within the Book class itself, you'll use static methods from the Comparator interface to define the sorting logic.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253package com.example; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Book> books = new ArrayList<>(); books.add(new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925)); books.add(new Book("To Kill a Mockingbird", "Harper Lee", 1960)); books.add(new Book("1984", "George Orwell", 1949)); // Sort by title books.sort(Comparator.comparing(Book::getTitle)); System.out.println("Sorted by title: " + books); System.out.println("------------------------"); // Sort by author books.sort(Comparator.comparing(Book::getAuthor)); System.out.println("Sorted by author: " + books); } } class Book { private String title; private String author; private int year; public Book(String title, String author, int year) { this.title = title; this.author = author; this.year = year; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } @Override public String toString() { return title + " by " + author + " (" + year + ")"; } }
In this example, you're using the Comparator interface to sort the books list. But why did you use the comparing() method instead of compare()?
If you want to use the compare() method, you need to create a Comparator object and implement the compare method.
public static Comparator<Book> titleComparator = new Comparator<Book>() {
@Override
public int compare(Book b1, Book b2) {
return b1.getTitle().compareTo(b2.getTitle());
}
};
This code defines a Comparator<Book> using an anonymous class to compare two Book objects by their title.
Since String implements Comparable, the compareTo() method is used to compare the titles lexicographically, returning a negative, zero, or positive value.
Alternatively, you can achieve the same result with a lambda expression for a more concise implementation:
(b1, b2) -> b1.getTitle().compareTo(b2.getTitle());
But there is an even simpler approach: using the Comparator.comparing() method. This method automatically handles the comparison logic for you, making it more readable and concise.
You simply pass a method reference that extracts the field for comparison.
Comparator.comparing(Book::getTitle)
The sort() method of the list calls the passed Comparator, which, in turn, determines the order of elements by comparing them based on the values returned by the specified methods.
Multiple Sorting
If you need to sort by multiple criteria, you can use the thenComparing method:
books.sort(
Comparator.comparing(Book::getYear) // First by year
.thenComparing(Book::getTitle) // Then by title
);
This example demonstrates how to sort a list of books first by their release year and then by title. The sorting process first compares the books based on their year, and if two books have the same year, it then compares them by title to determine their final order.
Reverse Sorting
Reversing the sorting order in Java is useful when you need to sort elements by one criterion first and then change the order for the next criterion.
The reversed() and Comparator.reverseOrder() methods help control sorting direction, but they function differently.
books.sort(
Comparator.comparing(Book::getYear).reversed() // Sort by year (descending)
.thenComparing(Book::getTitle, Comparator.reverseOrder()) // Then by title (descending)
);
The books are first sorted by their release year in descending order using reversed(). If multiple books share the same year, thenComparing() sorts them by title in reverse alphabetical order using Comparator.reverseOrder().
This ensures that the most recent books appear first, and within the same year, titles are ordered from Z to A.
Differences Between Comparable and Comparator
Use the Comparable interface when a class has a natural ordering, such as sorting by a single field. Use Comparator when sorting by multiple criteria or when you need to define a custom order for objects.
1. When to use the Comparable interface?
2. When to use the Comparator interface?
Thanks for your feedback!
Ask AI
Ask AI
Ask anything or try one of the suggested questions to begin our chat
Ask me questions about this topic
Summarize this chapter
Show real-world examples
Awesome!
Completion rate improved to 2.33
Comparator: Custom Comparison of Data
Swipe to show menu
Let's look at the second functional interface, Comparator, see how it implements comparison, and understand the difference between Comparator and Comparable.
What Is Comparator?
The key method in the Comparator functional interface is:
int compare(T o1, T o2);
The compare(T o1, T o2) method returns:
- A negative number if
o1is less thano2; - Zero if
o1ando2are equal; - A positive number if
o1is greater thano2.
Practical Application
Let's implement sorting of Book objects using the Comparator interface. Instead of implementing the comparison method within the Book class itself, you'll use static methods from the Comparator interface to define the sorting logic.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253package com.example; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Book> books = new ArrayList<>(); books.add(new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925)); books.add(new Book("To Kill a Mockingbird", "Harper Lee", 1960)); books.add(new Book("1984", "George Orwell", 1949)); // Sort by title books.sort(Comparator.comparing(Book::getTitle)); System.out.println("Sorted by title: " + books); System.out.println("------------------------"); // Sort by author books.sort(Comparator.comparing(Book::getAuthor)); System.out.println("Sorted by author: " + books); } } class Book { private String title; private String author; private int year; public Book(String title, String author, int year) { this.title = title; this.author = author; this.year = year; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } @Override public String toString() { return title + " by " + author + " (" + year + ")"; } }
In this example, you're using the Comparator interface to sort the books list. But why did you use the comparing() method instead of compare()?
If you want to use the compare() method, you need to create a Comparator object and implement the compare method.
public static Comparator<Book> titleComparator = new Comparator<Book>() {
@Override
public int compare(Book b1, Book b2) {
return b1.getTitle().compareTo(b2.getTitle());
}
};
This code defines a Comparator<Book> using an anonymous class to compare two Book objects by their title.
Since String implements Comparable, the compareTo() method is used to compare the titles lexicographically, returning a negative, zero, or positive value.
Alternatively, you can achieve the same result with a lambda expression for a more concise implementation:
(b1, b2) -> b1.getTitle().compareTo(b2.getTitle());
But there is an even simpler approach: using the Comparator.comparing() method. This method automatically handles the comparison logic for you, making it more readable and concise.
You simply pass a method reference that extracts the field for comparison.
Comparator.comparing(Book::getTitle)
The sort() method of the list calls the passed Comparator, which, in turn, determines the order of elements by comparing them based on the values returned by the specified methods.
Multiple Sorting
If you need to sort by multiple criteria, you can use the thenComparing method:
books.sort(
Comparator.comparing(Book::getYear) // First by year
.thenComparing(Book::getTitle) // Then by title
);
This example demonstrates how to sort a list of books first by their release year and then by title. The sorting process first compares the books based on their year, and if two books have the same year, it then compares them by title to determine their final order.
Reverse Sorting
Reversing the sorting order in Java is useful when you need to sort elements by one criterion first and then change the order for the next criterion.
The reversed() and Comparator.reverseOrder() methods help control sorting direction, but they function differently.
books.sort(
Comparator.comparing(Book::getYear).reversed() // Sort by year (descending)
.thenComparing(Book::getTitle, Comparator.reverseOrder()) // Then by title (descending)
);
The books are first sorted by their release year in descending order using reversed(). If multiple books share the same year, thenComparing() sorts them by title in reverse alphabetical order using Comparator.reverseOrder().
This ensures that the most recent books appear first, and within the same year, titles are ordered from Z to A.
Differences Between Comparable and Comparator
Use the Comparable interface when a class has a natural ordering, such as sorting by a single field. Use Comparator when sorting by multiple criteria or when you need to define a custom order for objects.
1. When to use the Comparable interface?
2. When to use the Comparator interface?
Thanks for your feedback!