You are currently viewing Sort Collections With Comparable and Comparator

Sort Collections With Comparable and Comparator

This entry is part 11 of 11 in the series Collections Framework

Introduction

The ability to Sort Collections effectively is a foundational skill in Java programming. Whether developers work with lists of domain objects, configuration data, or business entities, proper ordering ensures predictable behavior and enhances data readability. This article explains how to sort Collections using both Comparable and Comparator, highlights the differences between the two mechanisms, and provides practical examples.

1. Understanding Natural Ordering with Comparable

The Comparable interface defines an object’s natural order. When a type implements Comparable, it expresses how instances of that type should be ordered by default. This natural ordering is encoded directly in the class through the compareTo method.

As explained in our article on The Comparable interface in Java, “natural ordering belongs to the object itself.”

Below is an example of implementing natural ordering:

// Class implementing Comparable for natural order sorting
class Person implements Comparable<Person> {
    private String lastName;
    private String firstName;

    public Person(String lastName, String firstName) {
        this.lastName = lastName;
        this.firstName = firstName;
    }

    // Natural order: by lastName, then by firstName
    @Override
    public int compareTo(Person other) {
        int cmp = this.lastName.compareTo(other.lastName);
        if (cmp == 0) {
            return this.firstName.compareTo(other.firstName);
        }
        return cmp;
    }
}

This technique allows developers to sort Collections such as List<Person> without passing additional comparators.

2. Using Comparator for Custom and Flexible Sorting

While Comparable is useful for intrinsic ordering, many applications require multiple or dynamic sorting rules. The Comparator interface enables sorting without modifying the target class. This externalized comparison logic supports flexible and reusable ordering strategies.

As we emphasize in The Comparator interface in Java, “Comparator empowers behavior without modifying the underlying type.”

Example:

// Comparator for ordering persons by age
Comparator<Person> ageComparator = Comparator.comparingInt(Person::getAge);

This allows developers to sort Collections based on evolving business requirements.

3. Sorting Collections Using Collections.sort and List.sort

Java provides two main mechanisms to Sort Collections:

  • Collections.sort(list)
  • list.sort(comparator)

The second method is preferred in modern Java because it aligns with fluent API design and is defined directly on the List interface.

Example:

// Sorting using a custom comparator
List<Person> people = new ArrayList<>();
people.add(new Person("Dupont", "Alice", 30));
people.add(new Person("Martin", "Bruno", 45));
people.add(new Person("Dupont", "Chloe", 25));

people.sort(ageComparator); // Sort Collections by age using Comparator

Sorting methods in Java guarantee stability, meaning that elements considered equal retain their original order.

4. Multi-criteria Sorting with Comparator Composition

Business logic often requires multi-level sorting, such as ordering employees by last name, then first name, then age. The Comparator interface supports composition through methods like thenComparing.

Example:

// Multi-criteria sorting using Comparator composition
Comparator<Person> compositeComparator =
        Comparator.comparing(Person::getLastName)
                  .thenComparing(Person::getFirstName)
                  .thenComparingInt(Person::getAge);

This approach aligns with clean architecture principles and avoids deeply nested comparison logic.

5. Comparable vs. Comparator: A Summary of Differences

When sorting Collections, deciding between Comparable and Comparator is crucial. As summarized in our dedicated articles, Comparable and Comparator in Java, remembering the rule “Comparable defines default order; Comparator defines alternative order” helps clarify the distinction.

AspectComparableComparator
Location of logicInside the classExternal to the class
MethodcompareTo(T o)compare(T o1, T o2)
Use caseNatural/default orderingFlexible custom ordering
FlexibilityLowVery high
Modifies target class?YesNo
Supports composition?NoYes (thenComparing)

Choosing the right approach ensures maintainability and clarity in codebases that Sort Collections extensively.

Conclusion

Mastering techniques to Sort Collections is essential for writing maintainable and predictable Java applications. While Comparable defines natural ordering within the class, Comparator offers flexible and reusable external ordering strategies. As long as developers select the correct approach for the specific context, sorted data will remain consistent, clear, and easy to maintain. Sorting is a cornerstone operation in Java, and understanding its mechanisms lays the foundation for more advanced collection manipulation.

You can find the complete code for this article on GitHub.

Collections Framework

The Comparator Interface in Java

Noel Kamphoa

Experienced software engineer with expertise in Telecom, Payroll, and Banking. Now Senior Software Engineer at Societe Generale Paris.