Introduction
Java 8 introduced lambda expressions and functional interfaces, which have made it easier to work with collections and perform common tasks like sorting. The Comparator
interface is a functional interface that can be implemented using lambda expressions, making the code more concise and readable. Before Java 8, implementing a Comparator
required creating verbose anonymous classes. Now, with lambda expressions, you can implement Comparator
in a much simpler way.
In this guide, we’ll explore how to implement a Comparator
using functional interfaces in Java 8, focusing on using lambda expressions to simplify the code.
Table of Contents
- Problem Statement
- Solution Steps
- Java Program
- Example 1: Implementing
Comparator
Without Lambda Expressions - Example 2: Implementing
Comparator
with Lambda Expressions - Example 3: Implementing a
Comparator
for Custom Objects - Example 4: Combining Multiple Comparators
- Example 1: Implementing
- Conclusion
Problem Statement
Sorting collections based on custom criteria is a common task in Java. Traditionally, this required implementing the Comparator
interface using anonymous classes, which could be verbose and difficult to read. The goal is to implement Comparator
using lambda expressions to simplify the code and make it more maintainable.
Example:
- Problem: Writing custom sort logic using anonymous classes for
Comparator
can be verbose and harder to maintain. - Goal: Use lambda expressions to implement
Comparator
in a concise and readable way.
Solution Steps
- Implement
Comparator
Using Anonymous Classes: Demonstrate the traditional way of implementingComparator
without lambda expressions. - Simplify with Lambda Expressions: Use lambda expressions to implement
Comparator
more concisely. - Create Comparators for Custom Objects: Implement
Comparator
for custom objects likePerson
orProduct
. - Combine Multiple Comparators: Use method chaining to combine multiple
Comparator
implementations.
Java Program
Example 1: Implementing Comparator Without Lambda Expressions
Before Java 8, implementing Comparator
typically involved creating an anonymous class. Here’s how it was done:
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* Java 8 - Implement Comparator Without Lambda Expressions
* Author: https://www.rameshfadatare.com/
*/
public class ComparatorExample1 {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
// Implementing Comparator using an anonymous class
names.sort(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
System.out.println("Sorted Names: " + names);
}
}
Output
Sorted Names: [Alice, Bob, Charlie, John]
Explanation
- Anonymous Class: The
Comparator
interface is implemented using an anonymous class, which requires a significant amount of boilerplate code for a simple comparison task.
Example 2: Implementing Comparator with Lambda Expressions
Java 8 allows you to replace the anonymous class with a lambda expression, significantly simplifying the code.
import java.util.Arrays;
import java.util.List;
/**
* Java 8 - Implement Comparator with Lambda Expressions
* Author: https://www.rameshfadatare.com/
*/
public class ComparatorExample2 {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
// Implementing Comparator using a lambda expression
names.sort((s1, s2) -> s1.compareTo(s2));
System.out.println("Sorted Names: " + names);
}
}
Output
Sorted Names: [Alice, Bob, Charlie, John]
Explanation
- Lambda Expression: The lambda expression
(s1, s2) -> s1.compareTo(s2)
replaces the anonymous class. The code is now more concise and easier to read.
Example 3: Implementing a Comparator for Custom Objects
In this example, we implement a Comparator
for a custom Person
object based on the person’s age.
import java.util.Arrays;
import java.util.List;
/**
* Java 8 - Implement Comparator for Custom Objects
* Author: https://www.rameshfadatare.com/
*/
public class ComparatorExample3 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("John", 30),
new Person("Alice", 25),
new Person("Bob", 28),
new Person("Charlie", 32)
);
// Implementing Comparator for custom objects using lambda expression
people.sort((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));
System.out.println("People sorted by age: " + people);
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
Output
People sorted by age: [Alice (25), Bob (28), John (30), Charlie (32)]
Explanation
- Custom Objects: The lambda expression
(p1, p2) -> Integer.compare(p1.getAge(), p2.getAge())
sorts the list ofPerson
objects by age.
Example 4: Combining Multiple Comparators
You can chain multiple Comparator
instances to sort by more than one attribute. Here, we sort by name and then by age.
import java.util.Arrays;
import java.util.List;
/**
* Java 8 - Combine Multiple Comparators
* Author: https://www.rameshfadatare.com/
*/
public class ComparatorExample4 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("John", 30),
new Person("Alice", 25),
new Person("Bob", 28),
new Person("John", 25)
);
// Combining multiple comparators using method chaining
people.sort(
Comparator.comparing(Person::getName)
.thenComparing(Person::getAge)
);
System.out.println("People sorted by name and age: " + people);
}
}
Output
People sorted by name and age: [Alice (25), Bob (28), John (25), John (30)]
Explanation
- Method Chaining: The
Comparator.comparing(Person::getName).thenComparing(Person::getAge)
sorts the list first by name and then by age, demonstrating how to combine multiple comparators using method chaining.
Conclusion
Implementing Comparator
with lambda expressions in Java 8 simplifies the process of sorting collections, making the code more concise and readable. Whether you’re sorting simple lists of strings or complex objects like Person
, lambda expressions provide a clean and efficient way to implement custom sorting logic. Additionally, by chaining multiple Comparator
instances, you can create complex sorting behavior in a very concise manner, improving the maintainability and clarity of your code.