Learn about Comparators for flexible object comparison and how to use Java's built-in sorting mechanisms.
While the Comparable interface provides a natural ordering for a class, the Comparator interface allows you to define multiple custom orderings for objects without modifying their classes.
The Comparator interface has a single abstract method to implement:
public interface Comparator<T> { int compare(T o1, T o2); }
Similar to compareTo(), the compare() method should:
// A comparator that sorts Product objects by price public class ProductPriceComparator implements Comparator<Product> { @Override public int compare(Product p1, Product p2) { // Compare prices return p1.getPrice().compareTo(p2.getPrice()); } } // A comparator that sorts Product objects by title public class ProductTitleComparator implements Comparator<Product> { @Override public int compare(Product p1, Product p2) { // Compare titles alphabetically return p1.getTitle().compareTo(p2.getTitle()); } }
Java provides several ways to sort collections of objects:
// Sorting by natural ordering (using Comparable) List<String> names = Arrays.asList("Charlie", "Alice", "Bob"); Collections.sort(names); // ["Alice", "Bob", "Charlie"] // Sorting with a Comparator List<Product> products = getProductList(); Collections.sort(products, new ProductPriceComparator()); // Sorted by price Collections.sort(products, new ProductTitleComparator()); // Sorted by title
// Sorting an array of Comparable objects String[] namesArray = {"Charlie", "Alice", "Bob"}; Arrays.sort(namesArray); // Sorting an array with a Comparator Product[] productsArray = getProductArray(); Arrays.sort(productsArray, new ProductPriceComparator());
For complex sorting requirements, you can chain multiple comparisons:
public class ProductPriceRatingComparator implements Comparator<Product> { @Override public int compare(Product p1, Product p2) { // First compare by price int priceComparison = p1.getPrice().compareTo(p2.getPrice()); // If prices are equal, compare by rating if (priceComparison == 0) { return Double.compare(p2.getRating(), p1.getRating()); // Higher rating first } return priceComparison; } }
In modern Java, you can use lambda expressions to create Comparators concisely:
// Sorting by price Collections.sort(products, (p1, p2) -> p1.getPrice().compareTo(p2.getPrice())); // Sorting by title Collections.sort(products, (p1, p2) -> p1.getTitle().compareTo(p2.getTitle())); // Chaining comparisons using Comparator methods Comparator<Product> comparator = Comparator .comparing(Product::getPrice) .thenComparing(Product::getRating, Comparator.reverseOrder()) .thenComparing(Product::getTitle); Collections.sort(products, comparator);
To reverse the ordering of a Comparator:
// Using the reversed() method (Java 8+) Collections.sort(products, new ProductPriceComparator().reversed()); // For natural ordering, use reverseOrder() Collections.sort(names, Comparator.reverseOrder());
Decision guidelines for choosing between Comparator and Comparable:
Criterion | Comparable | Comparator |
---|---|---|
Control over class | Need to modify class | No need to modify class |
Ordering types | Single natural ordering | Multiple orderings possible |
Usage with sort | Collections.sort(list) | Collections.sort(list, comparator) |
Common examples | String, Integer, Date | Custom sorting strategies |