Package relations: + java.util + - java.lang.Comparator<T>

Parameter type: T - the type of objects that may be compared by this comparator

This is a functional interface.


The Comparator is a functional interface that used to define a custom ordering for objects. This interface is useful for sorting a collection of objects that is different from their natural ordering, or when objects do not have a natural ordering using collections sort. The Comparator interface has a single abstract method compare() and several default methods.

Difference between Comparable and Comparator

Comparable lets the object define its own default comparison (natural ordering).   Comparator is for when you want to define a custom comparison.

compare()

The compare() is an abstract method that compares two arguments for order.

int compare(T o1, T o2);

This method returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

Implement with anonymous nested class

You can implement the Comparator interface and override the compare() method using anonymous nested class. The comparator is then used by the collections sort method for sorting Person objects using custom ordering. In this case we use the compare() method from Integer class for defining the custom ordering.

public class Person {  
    int age;  
    String name;  
    
    public Person(int age, String name) {  
        this.age = age;  
        this.name = name;  
    }  
    
    @Override  
    public String toString() {  
        return "[" + "Name: " + name + ", Age: " + age + "]";  
    }  
}
public static void main(String[] args) {  
    List<Person> people = new ArrayList<>();  
    people.add(new Person(12, "Tim"));  
    people.add(new Person(31, "John"));  
    people.add(new Person(23, "Jason"));  
	
	// implement using anonymous nested class
	// the custom ordering is defined by Integer.compare()
	// this will sort the ages in ascending order
    Comparator<Person> ageComparator = new Comparator<Person>() {  
        @Override  
        public int compare(Person o1, Person o2) {  
            return Integer.compare(o1.age, o2.age);  
        }  
    };
    // sort with collections
    Collections.sort(people, ageComparator);  
	System.out.println(people);
}
[[Name: Tim, Age: 12], [Name: Jason, Age: 23], [Name: John, Age: 31]]

Implement with lambda expression

Use Integer.compare()

The below is the implementation of the Comparator interface using lambda expression.

public static void main(String[] args) {  
    List<Person> people = new ArrayList<>();  
    people.add(new Person(12, "Tim"));  
    people.add(new Person(31, "John"));  
    people.add(new Person(23, "Jason"));  
	
	// implement using lambda expression
	Comparator<Person> ageComparator = (Person o1, Person o2) -> Integer.compare(o1.age, o2.age); 
    Collections.sort(people, ageComparator);  
	System.out.println(people);
}
[[Name: Tim, Age: 12], [Name: Jason, Age: 23], [Name: John, Age: 31]]

It can be further simplified as:

//...
	Comparator<Person> ageComparator = (o1, o2) -> Integer.compare(o1.age, o2.age); 
    Collections.sort(people, ageComparator);  
	System.out.println(people);

Use Comparator.comparingInt()

We can also use the static method comparingInt() that comes with the Comparator interface to produce the same outcome.

List<Person> people = new ArrayList<>();  
// ...
 
Comparator<Person> ageComparator = Comparator.comparingInt((Person o) -> o.age);
Collections.sort(people, ageComparator);  
System.out.println(people);

The comparingInt() method takes a ToIntFunction, which is a functional interface that extracts an integer from an object.

public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {  
    Objects.requireNonNull(keyExtractor);  
    return (Comparator<T> & Serializable)  
        (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));  
}
@FunctionalInterface  
public interface ToIntFunction<T> {  int applyAsInt(T value);  }

In our case:

(Person o) -> o.age

This lambda expression is equivalent to implementing the applyAsInt() method of the ToIntFunction interface. The applyAsInt() method takes an object of type T (here, a Person) and returns an integer (the age). The comparingInt() method will create and return a Comparator (it is also Serializable) that compares two Person objects (c1 and c2) by comparing the integers extracted using the applyAsInt() method. Internally, it uses:

Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));

(Learning lambda expression in Lambda Expressions and more practical examples in Stream API)

Comparator default methods

MethodDescription
static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)It accepts a function that extracts an int sort key from a type T, and returns a Comparator that compares by that sort key
static <T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor)It accepts a function that extracts a double sort key from a type T, and returns a Comparator that compares by that sort key

Back to parent page: Java Standard Edition (Java SE) and Java Programming

Web_and_App_Development Programming_Languages Java Comparator Lambda_Expression Anonymous_Nested_Class