Java 8 – Implement Comparator Using Functional Interfaces

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
  • 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

  1. Implement Comparator Using Anonymous Classes: Demonstrate the traditional way of implementing Comparator without lambda expressions.
  2. Simplify with Lambda Expressions: Use lambda expressions to implement Comparator more concisely.
  3. Create Comparators for Custom Objects: Implement Comparator for custom objects like Person or Product.
  4. 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 of Person 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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top