Understanding the Comparator Interface in Java 8

Understanding the Comparator Interface in Java 8

Published: February 22, 2016


Introduction

Java 8 introduced many new features that make working with collections more powerful and efficient. One of these features is the Comparator interface, which allows developers to sort objects in a collection based on specific criteria.

In this tutorial, we’ll cover:

  • What the Comparator interface is and why it’s useful.
  • How to implement and use a comparator to sort objects in Java.
  • How to use the new sorting methods introduced in Java 8.

What is a Comparator?

Comparator is an interface in the java.util package that provides a way to define custom sorting logic for objects in a collection. The interface has two main methods:

  1. compare(T o1, T o2) – Compares two objects of the same type.
  2. reversed() – Returns a comparator that imposes the reverse order of the original comparator.

Before Java 8, sorting was often done by implementing the Comparable interface in the objects you wanted to sort. However, using Comparator allows you to sort objects based on external criteria, without modifying the original class.


Using the Comparator Interface

Let’s look at an example where we have a list of Employee objects, and we want to sort them by their salary and name.

Creating the Employee Class

public class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', salary=" + salary + '}';
    }
}

Sorting Using a Comparator

We will now sort a list of Employee objects based on their salary and name. First, let’s create a Comparator to sort by salary.

import java.util.*;

public class ComparatorExample {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
            new Employee("Alice", 50000),
            new Employee("Bob", 60000),
            new Employee("Charlie", 45000)
        );

        // Sorting by salary using Comparator
        Comparator<Employee> salaryComparator = Comparator.comparingDouble(Employee::getSalary);
        employees.sort(salaryComparator);

        System.out.println("Employees sorted by salary:");
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
}

Output:

Employees sorted by salary:
Employee{name='Charlie', salary=45000.0}
Employee{name='Alice', salary=50000.0}
Employee{name='Bob', salary=60000.0}

In the example above, we used Comparator.comparingDouble() to sort employees based on their salary in ascending order.


Sorting by Multiple Criteria

You can also chain multiple Comparator instances to perform multi-level sorting. For example, let’s sort by salary first and then by name.

Comparator<Employee> multiCriteriaComparator = Comparator
    .comparingDouble(Employee::getSalary)
    .thenComparing(Employee::getName);

employees.sort(multiCriteriaComparator);

System.out.println("Employees sorted by salary and name:");
for (Employee employee : employees) {
    System.out.println(employee);
}

Output:

Employees sorted by salary and name:
Employee{name='Charlie', salary=45000.0}
Employee{name='Alice', salary=50000.0}
Employee{name='Bob', salary=60000.0}

In this case, employees are first sorted by salary. If two employees have the same salary, they are sorted by name.


Using Lambda Expressions with Comparator

In Java 8, you can use lambda expressions to simplify the implementation of comparators. This makes the code more concise and readable.

Sorting by Salary Using Lambda Expression

Comparator<Employee> salaryComparatorLambda = (e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary());
employees.sort(salaryComparatorLambda);

System.out.println("Employees sorted by salary (Lambda):");
for (Employee employee : employees) {
    System.out.println(employee);
}

Output:

Employees sorted by salary (Lambda):
Employee{name='Charlie', salary=45000.0}
Employee{name='Alice', salary=50000.0}
Employee{name='Bob', salary=60000.0}

As you can see, the lambda expression makes the comparator much more concise.


Reversed Sorting

Java 8 also allows you to easily reverse the order of a comparator using the reversed() method.

Comparator<Employee> reversedComparator = salaryComparator.reversed();
employees.sort(reversedComparator);

System.out.println("Employees sorted by salary (reversed):");
for (Employee employee : employees) {
    System.out.println(employee);
}

Output:

Employees sorted by salary (reversed):
Employee{name='Bob', salary=60000.0}
Employee{name='Alice', salary=50000.0}
Employee{name='Charlie', salary=45000.0}

Using Comparator with Collections.sort()

Instead of using employees.sort(comparator), you can also use Collections.sort():

Collections.sort(employees, salaryComparator);

This will sort the employees list using the provided comparator.


Conclusion

The Comparator interface is a powerful tool for sorting collections in Java 8. It provides flexible ways to define custom sorting logic for objects, allowing you to easily sort by one or more criteria, use lambda expressions, reverse the order, and much more.

In the next tutorial, we will explore The forEach() Method in Java 8, and how it simplifies iteration over collections.


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

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