Comparator interface in Java

Sameera De Silva
6 min readNov 25, 2023

--

The Comparator interface in Java is part of the java.util package
Java Comparator interface is used to order the objects of a user-defined class.
A comparator object is capable of comparing two objects of the same class.
It’s often used for sorting collections of objects or for providing a custom ordering for objects.

The Comparator interface has a single method:

int compare(T o1, T o2);

Here, o1 and o2 are the objects to be compared.
The compare method returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

This method is used by various sorting algorithms, like those used in the Collections.sort method.

Coding example

Here, lets compare a list of Apples by their country and then the colour.

package com.comparatorexample;

class Apple {
String country;
int weight;
String color;

public Apple(String country, int weight, String color) {
this.country = country;
this.weight = weight;
this.color = color;
}
}

The class with the the main method

package com.comparatorexample;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class MultiValueComparatorExample {

// Using Comparator interface ,first sort apples by country then colour.

public static void main(String[] args) {
List<Apple> myAppleList = new ArrayList<>();
myAppleList.add(new Apple("USA", 400, "red"));
myAppleList.add(new Apple("China", 700, "yellow"));
myAppleList.add(new Apple("England", 340, "pink"));
myAppleList.add(new Apple("Australia", 500, "green"));
myAppleList.add(new Apple("China", 300, "Orange"));
myAppleList.add(new Apple("China", 400, "yellow"));
myAppleList.add(new Apple("India", 800, "Red"));


// Sorting by country, then by color using a compound comparator

/* This code is using the Collections.sort method to sort a list of Apple objects (myAppleList).
The second argument to Collections.sort is a Comparator implementation,
which defines how the elements in the list should be compared for sorting.

Here's a breakdown of the code:

Collections.sort(apples, ...) - This is the method call to sort the list apples.

new Comparator<Apple>() { ... } -
This is an anonymous class that implements the Comparator interface.
It's used to define the comparison logic for the sorting.


The type argument for the Comparator is specified as Apple.
This means that the Comparator will be responsible for comparing objects of type Apple.
The compare method within the Comparator is then implemented to define how two Apple objects should be compared for sorting.

@Override - This annotation indicates that the compare method is intended to override a method in a superclass
(in this case, the compare method from the Comparator interface).

public int compare(Apple apple1, Apple apple2) - This is the implementation of the compare method.
It takes two Apple objects, apple1 and apple2, and returns an integer.
The integer should be negative if apple1 should be placed before apple2 in the sorted order,
zero if they are considered equal in terms of sorting, and positive if apple1 should be placed after apple2.

Inside the compare method, you define the logic for comparing the Apple objects.
Depending on your requirements, you can customize the logic to compare objects based on the criteria
that matter to you for sorting.
*/

Collections.sort(myAppleList, new Comparator<Apple>() {
@Override
public int compare(Apple apple1, Apple apple2) {
// first Compare by country
int countryComparison = apple1.country.compareTo(apple2.country);

// If countries are equal, compare by color
if (countryComparison == 0) {
return apple1.color.compareTo(apple2.color);
}

return countryComparison;
}
});

// Print the sorted list
for (Apple apple : myAppleList) {
System.out.println("Country: " + apple.country +
", Weight: " + apple.weight +
", Color: " + apple.color);
}
}
}

Output-

Country: Australia, Weight: 500, Color: green
Country: China, Weight: 300, Color: Orange
Country: China, Weight: 700, Color: yellow
Country: China, Weight: 400, Color: yellow
Country: England, Weight: 340, Color: pink
Country: India, Weight: 800, Color: Red
Country: USA, Weight: 400, Color: red

Similarities between comparable interface and Compator interface

Difference between comparable interface and Compator interface

Key differences explanation

1.Comparable interface is used to sort the objects with natural ordering. while Comparator interface used for custom sorting.

The Comparable interface in Java is used to define the natural ordering of objects.
When a class implements the Comparable interface, it means that its instances can be compared with each other based on their natural order.

The Comparable interface has a single method: compareTo(Object obj). The implementing class provides the logic for comparing itself with another object

2.The Comparable interface only provides a single sorting sequence, meaning you can sort objects based on only one criterion.
This is why you can only sort apples by colour or country using the Comparable interface.

To sort objects based on multiple criteria, you need to use the Comparator interface.
The Comparator interface provides a more flexible way to compare objects, allowing you to define custom comparison logic that can consider multiple fields or properties.

In your example with the Apple class, let's say you want to sort apples first by country, then by weight, and finally by colour.

package com.comparatorexample;

import java.util.Comparator;

public class AppleComparator implements Comparator<Apple> {

@Override
public int compare(Apple apple1, Apple apple2) {
// Compare by country
int countryComparison = apple1.country.compareTo(apple2.country);
if (countryComparison != 0) {
return countryComparison;
}

// If countries are the same, compare by weight
int weightComparison = Integer.compare(apple1.weight, apple2.weight);
if (weightComparison != 0) {
return weightComparison;
}

// If weights are the same, compare by color
return apple1.color.compareTo(apple2.color);
}
}

Now, you can use this Comparator to sort a list of Apple objects with multiple criteria:

package com.comparatorexample;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
apples.add(new Apple("USA", 150, "Red"));
apples.add(new Apple("India", 120, "Green"));
apples.add(new Apple("USA", 200, "Yellow"));
apples.add(new Apple("India", 120, "Red"));
apples.add(new Apple("Canada", 180, "Green"));

// Use the custom comparator
Collections.sort(apples, new AppleComparator());

// Print the sorted list
for (Apple apple : apples) {
System.out.println(apple.country + ", " + apple.weight + ", " + apple.color);
}
}
}

Output-

Canada, 180, Green
India, 120, Green
India, 120, Red
USA, 150, Red
USA, 200, Yellow

Note-
It is possible to achieve multiple sorting criteria using the Comparable interface by implementing a custom compareTo() method
that compares objects based on multiple fields.
However, this approach can become cumbersome and difficult to maintain, especially as the number of sorting criteria increases

3. Comparable interface modifies the original class.
While comparator interface has no modification to the original class.

When a class implements the Comparable interface, the compareTo method is typically implemented within the class itself.

public class Apple implements Comparable<Apple> {

This method defines the natural ordering of instances of that class.
The Comparable interface is part of the class’s contract, and the implementation directly impacts how instances of the class are naturally ordered.
Since the compareTo method is part of the class, modifying it affects the original class.

However,the Comparator interface is separate from the class it is comparing. It allows you to define multiple ways of comparing objects without modifying their original class.

Let’s look at it .

To create Apple

package com.Comparatormultipleseparate;

class Apple {
String country;
int weight;
String color;

public Apple(String country, int weight, String color) {
this.country = country;
this.weight = weight;
this.color = color;
}
// Getters and other methods...

@Override
public String toString() {
return "Apple{" +
"country='" + country + '\'' +
", weight=" + weight +
", color='" + color + '\'' +
'}';
}

}

Three separate Comparators to sort by weight , country and color respectively.

package com.Comparatormultipleseparate;

import java.util.Comparator;

public class AppleComparatorByWeight implements Comparator<Apple> {
@Override
public int compare(Apple apple1, Apple apple2) {
return Integer.compare(apple1.weight, apple2.weight);
// Weight is integer
}
}
package com.Comparatormultipleseparate;

import java.util.Comparator;

public class AppleComparatorByCountry implements Comparator<Apple> {
@Override
public int compare(Apple apple1,Apple apple2) {
// Here is a String comparison
return apple1.country.compareTo(apple2.country);
}
}
package com.Comparatormultipleseparate;

import java.util.Comparator;

public class AppleComparatorByColor implements Comparator<Apple> {
@Override
public int compare(Apple apple1, Apple apple2) {
// String comparison
return apple1.color.compareTo(apple2.color);
}
}

Main method

package com.Comparatormultipleseparate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {
public static void main(String[] args) {
List<Apple> myAppleList = new ArrayList<>();
myAppleList.add(new Apple("USA", 400, "red"));
myAppleList.add(new Apple("China", 700, "yellow"));
myAppleList.add(new Apple("England", 340, "pink"));
myAppleList.add(new Apple("Australia", 500, "green"));
myAppleList.add(new Apple("China", 300, "Orange"));
myAppleList.add(new Apple("China", 400, "yellow"));
myAppleList.add(new Apple("India", 800, "Red"));

String choice = "ByWeight"; // You can change this to "ByCountry" or "ByColor"
//Define a comparator type of Apple
Comparator<Apple> comparator;
//Based on the choice , call the predefined Comparator.
switch (choice) {
case "ByWeight":
comparator = new AppleComparatorByWeight();
// new keyword used to instantiate an object of a class that implements the Comparator interface.
break;
case "ByCountry":
comparator = new AppleComparatorByCountry();
break;
case "ByColor":
comparator = new AppleComparatorByColor();
break;
default:
throw new IllegalArgumentException("Invalid choice");
}

// Sort the list based on the chosen comparator
Collections.sort(myAppleList, comparator);

// Print the sorted list
for (Apple apple : myAppleList) {
System.out.println(apple);
}
}
}

Output -

Apple{country='China', weight=300, color='Orange'}
Apple{country='England', weight=340, color='pink'}
Apple{country='USA', weight=400, color='red'}
Apple{country='China', weight=400, color='yellow'}
Apple{country='Australia', weight=500, color='green'}
Apple{country='China', weight=700, color='yellow'}
Apple{country='India', weight=800, color='Red'}

--

--