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
ComparatorWithout Lambda Expressions - Example 2: Implementing
Comparatorwith Lambda Expressions - Example 3: Implementing a
Comparatorfor 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
Comparatorcan be verbose and harder to maintain. - Goal: Use lambda expressions to implement
Comparatorin a concise and readable way.
Solution Steps
- Implement
ComparatorUsing Anonymous Classes: Demonstrate the traditional way of implementingComparatorwithout lambda expressions. - Simplify with Lambda Expressions: Use lambda expressions to implement
Comparatormore concisely. - Create Comparators for Custom Objects: Implement
Comparatorfor custom objects likePersonorProduct. - Combine Multiple Comparators: Use method chaining to combine multiple
Comparatorimplementations.
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
Comparatorinterface 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 ofPersonobjects 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.