is Comparator.comparing() used for converting a single argument lambda expression to a double argument?

Yes, you can sort of think of it like that.

When sorting things, you are supposed to specify "given two things a and b, which of them is greater, or are they equal?" using a Comparator<T>. The a and b is why it has 2 lambda parameters, and you return an integer indicating your answer to that question.

However, a much more convenient way to do this is to specify "given a thing x, what part of x do you want to sort by?". And that is what you can do with the keyExtractor argument of Comparator.comparing.

Compare:

/*
given two people, a and b, the comparison result between a and b is the 
comparison result between a's name and b's name
*/
Comparator<Person> personNameComparator = 
    (a, b) -> a.getName().compareTo(b.getName());

/*
given a person x, compare their name
*/
Comparator<Person> personNameComparator = 
    Comparator.comparing(x -> x.getName()); // or Person::getName

The latter is clearly much more concise and intuitive. We tend to think about what things to sort by, rather than how exactly to compare two things, and the exact number to return depending on the comparison result.

As for the declaration for comparing:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)

The <T, U extends Comparable<? super U>> part first declares two generic type parameters - T is what the comparator compares (Person in the above case), and U is the type that you are actually comparing (String in the above case), hence it extends Comparable.

keyExtractor is the parameter you pass in, such as x -> x.getName(), that should answer the question of "when given a T, what is a U that you want to compare by?".

If you are confused by the ? super and ? extends, read What is PECS?.

If you haven't realised already, the implementation of comparing basically boils down to:

return (a, b) -> keyExtractor.apply(a).compareTo(keyExtractor.apply(b));
Answer from Sweeper on Stack Overflow
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › Comparator.html
Comparator (Java Platform SE 8 )
October 20, 2025 - Returns a lexicographic-order comparator with a function that extracts a key to be compared with the given Comparator.
🌐
Baeldung
baeldung.com › home › java › core java › comparator and comparable in java
Comparator and Comparable in Java | Baeldung
March 26, 2025 - Comparator<Player> byRanking = Comparator .comparing(Player::getRanking); Comparator<Player> byAge = Comparator .comparing(Player::getAge); To explore the Java 8 functionality in-depth, check out our Java 8 Comparator.comparing guide.
🌐
Baeldung
baeldung.com › home › java › guide to java comparator.comparing()
Guide to Java Comparator.comparing() | Baeldung
January 8, 2024 - There’s another option that facilitates overriding the natural ordering of the sort key by providing a Comparator that creates a custom ordering for the sort key: static <T,U> Comparator<T> comparing( Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
🌐
GeeksforGeeks
geeksforgeeks.org › java › java-comparator-interface
Java Comparator Interface - GeeksforGeeks
Uses Comparator (lambda expression) to sort students by id. Collections.sort() applies the custom sorting logic.
Published   April 20, 2016
Top answer
1 of 4
14

is Comparator.comparing() used for converting a single argument lambda expression to a double argument?

Yes, you can sort of think of it like that.

When sorting things, you are supposed to specify "given two things a and b, which of them is greater, or are they equal?" using a Comparator<T>. The a and b is why it has 2 lambda parameters, and you return an integer indicating your answer to that question.

However, a much more convenient way to do this is to specify "given a thing x, what part of x do you want to sort by?". And that is what you can do with the keyExtractor argument of Comparator.comparing.

Compare:

/*
given two people, a and b, the comparison result between a and b is the 
comparison result between a's name and b's name
*/
Comparator<Person> personNameComparator = 
    (a, b) -> a.getName().compareTo(b.getName());

/*
given a person x, compare their name
*/
Comparator<Person> personNameComparator = 
    Comparator.comparing(x -> x.getName()); // or Person::getName

The latter is clearly much more concise and intuitive. We tend to think about what things to sort by, rather than how exactly to compare two things, and the exact number to return depending on the comparison result.

As for the declaration for comparing:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)

The <T, U extends Comparable<? super U>> part first declares two generic type parameters - T is what the comparator compares (Person in the above case), and U is the type that you are actually comparing (String in the above case), hence it extends Comparable.

keyExtractor is the parameter you pass in, such as x -> x.getName(), that should answer the question of "when given a T, what is a U that you want to compare by?".

If you are confused by the ? super and ? extends, read What is PECS?.

If you haven't realised already, the implementation of comparing basically boils down to:

return (a, b) -> keyExtractor.apply(a).compareTo(keyExtractor.apply(b));
2 of 4
7

Comparator#compare(T o1, T o2) Compare two objects and returns an integer value based on this criteria:

  • A negative value if o1 < o2
  • A positive value if o1 > o2
  • Zero if they are equal.

Comparator.comparing(Function<? super T, ? extends U> key) returns a Comparator<T> that compares by that sort key.

The main difference is that compare method provides a single point of comparison, whereas comparing chained to other functions to provide multiple points of comparison.

Suppose you have a class Person

public class Person implements Comparable<Person> {
    private String firstName;
    private String lastName;
    private int age;
    // rest of class omitted
}

if you compare two Person instances p1 vs p2 using compare(p1, p2), the comparison will be executed and the two objects will be sorted based on some natural ordering prescribed by the class. In contrast, if you want to compare the same two instances using comparing(), the comparison will be executed based on whichever criteria you choose to compare based on some attribute of the class. For example: Comparator.comparing(Person::getFirstName).

Because comparing returns a Comparator rather than a value, as I stated before, you can chain multiple comparisons. For instance: Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName);

As for the meaning of the return type <T, U extends Comparable<? super U>> Comparator<T>, you can find the explanation here.

I want to add that, classes must be comparable in order for compare(T o1, T o2) to work. String objects are comparable because they implement this interface. That said, if a class is not Comparable, you can still use comparing method because as I stated, you get to choose which attribute of the class you would like to use for the comparison and those attributes are likely to be comparable (i.e. String in the case of person's name or age in the above example).

🌐
Medium
medium.com › @AlexanderObregon › javas-comparator-comparing-method-explained-342361288af6
Java’s Comparator.comparing() Method Explained | Medium
October 2, 2024 - Java’s Comparator.comparing() method is a powerful tool that simplifies custom sorting based on object properties. By allowing us to create comparators for sorting collections like lists, this method reduces the complexity of implementing ...
🌐
LabEx
labex.io › tutorials › java-how-to-compare-objects-with-custom-comparator-in-java-419620
How to compare objects with custom comparator in Java | LabEx
It provides a way to compare two objects and determine their order, which is particularly useful when you want to sort collections or implement custom sorting mechanisms. The Comparator interface contains a single abstract method: ... import ...
🌐
Javatpoint
javatpoint.com › Comparator-interface-in-collection-framework
Java Comparator - javatpoint
Java Comparator interface is used to order the user-defined class objects, compare() method, collection class, java comporator example, Example of Comparator interface in collection framework.
Find elsewhere
Top answer
1 of 9
117

I recommend you create an enum for your car colours instead of using Strings and the natural ordering of the enum will be the order in which you declare the constants.

public enum PaintColors {
    SILVER, BLUE, MAGENTA, RED
}

and

 static class ColorComparator implements Comparator<CarSort>
 {
     public int compare(CarSort c1, CarSort c2)
     {
         return c1.getColor().compareTo(c2.getColor());
     }
 }

You change the String to PaintColor and then in main your car list becomes:

carList.add(new CarSort("Ford Figo",PaintColor.SILVER));

...

Collections.sort(carList, new ColorComparator());
2 of 9
82

How about this:

List<String> definedOrder = // define your custom order
    Arrays.asList("Red", "Green", "Magenta", "Silver");

Comparator<Car> comparator = new Comparator<Car>(){

    @Override
    public int compare(final Car o1, final Car o2){
        // let your comparator look up your car's color in the custom order
        return Integer.valueOf(
            definedOrder.indexOf(o1.getColor()))
            .compareTo(
                Integer.valueOf(
                    definedOrder.indexOf(o2.getColor())));
    }
};

In principle, I agree that using an enum is an even better approach, but this version is more flexible as it lets you define different sort orders.

Update

Guava has this functionality baked into its Ordering class:

List<String> colorOrder = ImmutableList.of("red","green","blue","yellow");
final Ordering<String> colorOrdering = Ordering.explicit(colorOrder);
Comparator<Car> comp = new Comparator<Car>() {
    @Override
    public int compare(Car o1, Car o2) {
        return colorOrdering.compare(o1.getColor(),o2.getColor());
    }
}; 

This version is a bit less verbose.


Update again

Java 8 makes the Comparator even less verbose:

Comparator<Car> carComparator = Comparator.comparing(
        c -> definedOrder.indexOf(c.getColor()));
🌐
DigitalOcean
digitalocean.com › community › tutorials › comparable-and-comparator-in-java-example
Comparable and Comparator in Java Example | DigitalOcean
August 3, 2022 - Java provides Comparable interface which should be implemented by any custom class if we want to use Arrays or Collections sorting methods. The Comparable interface has compareTo(T obj) method which is used by sorting methods, you can check any Wrapper, String or Date class to confirm this.
🌐
Blogger
javarevisited.blogspot.com › 2021 › 09 › comparator-comparing-thenComparing-example-java-.html
Java 8 Comparator comparing() and thenComparing() Example - Tutorial
Overall these new Comparator methods make comparing objects really easy and fun as you can also pass both lambda expression and method reference to this method, making it super easy to write custom Comparators on the fly as shown in the following example but before that let's create a custom Java object or POJO (Plain Old Java object to demonstrate this comparison and sorting example in Java.
🌐
Benchresources
benchresources.net › home › java › java 8 – comparator.comparing() method for custom/reverse sorting
Java 8 – Comparator.comparing() method for custom/reverse sorting - BenchResources.Net
October 18, 2021 - package net.bench.resources.comparator.comparing.custom; import java.util.Arrays; import java.util.Comparator; import java.util.List; public class SortProductListByNameInReverseOrder { // List of Products private static List<Product> getProductList() { return Arrays.asList( new Product(101, "Wheat", 1089L, 36.89), new Product(102, "Rice", 502L, 58.19), new Product(103, "Lentils", 803L, 102.45), new Product(104, "Oil", 208L, 164.75), new Product(105, "Vegetables", 303L, 45.50) ); } // main() method public static void main(String[] args) { // 1.
🌐
Gitbook
gyansetu-core-java-for-java.gitbook.io › project › untitled-1 › creating-and-using-list-set-and-deque-implementations › custom-sorting-using-comparator
Custom Sorting using comparator | Core java - Advance Topics
For such cases, Java provides a Comparator interface. You can define a Comparator and pass it to the sorting functions like Collections.sort or Arrays.sort to sort the objects based on the ordering defined by the Comparator.
🌐
Dev.java
dev.java › learn › writing-and-combining-comparators
Dev
The Foreign Function and Memory (FFM) API facilitates Java programs to interoperate with code and data outside the Java runtime without the brittleness and danger of JNI. ... Understand how the module system shapes the JDK and how you can use it to make your code base more maintainable. Creating Runtime and Application Images with JLink · Learn how to use the command line tool jlink to create custom...
🌐
Dev.java
dev.java › learn › lambdas › writing-comparators
Writing and Combining Comparators - Dev.java
Suppose you need to create a comparator to compare strings of characters in a non-natural way: the shortest strings are lesser than the longest strings. ... You learned in the previous part that it is possible to chain and compose lambda expressions. This code is another example of such a composition. Indeed, you can rewrite it in that way: Function<String, Integer> toLength = String::length; Comparator<String> comparator = (s1, s2) -> Integer.compare( toLength.apply(s1), toLength.apply(s2));
🌐
Tutorialspoint
tutorialspoint.com › home › java › java comparator example
Java Comparator Example
September 1, 2008 - In Java, the Comparator interface is a part of java.util package and it defines the order of the objects of user-defined classes.
Top answer
1 of 2
2

You should consider using the native language/library support for work like this.

Let me prime that, by adding this private function to your clas:

private Integer getTransNombre() {
    return transportista == null ? null : transportista.getNombre();
}

That gets the number, if the transportista is not null. Now, using that function, we can create a reusable comparator instance using the tricks that Java 8 introduces. Consider these chained comparators:

private static final Comparator<SeguimientoSeccion> COMP = Comparator.comparing(SeguimientoSeccion::getYear)
        .thenComparing(SeguimientoSeccion::getMonth)
        .thenComparing(SeguimientoSeccion::getFijacion, Comparator.nullsLast(Comparator.naturalOrder()))
        .thenComparing(SeguimientoSeccion::getTransNombre, Comparator.nullsLast(Comparator.naturalOrder()));

How does that work? It gets details about the instances, if they compare as "equals" then the next test is run. You can sort nulls to the end, and you can go from there.

If you still need your comparator class, it could be:

public class SeguimientoSeccionComparator implements Comparator<SeguimientoSeccion> {
    public int compare(SeguimientoSeccion o1, SeguimientoSeccion o2) {
        return COMP.compare(o1, o2);
    }
}
2 of 2
1

Given

/** Note: this class has a natural ordering
 *        that is inconsistent with equals. */
static class Transportista
    implements Comparable<Transportista> {
    String nombre;
    String getNombre() { return nombre; }
    @Override
    public int compareTo(Transportista o) { return 0; }
}
/** mock Java 8 nullsLast comparison */
static int nullsLast(Comparable c, Comparable x) {
    if (c == x)
        return 0;
    if (null == c)
        return 1;
    if (null == x)
        return -1;
    return c.compareTo(x); 
}

, compare() could look

/** by {@code year, month, fijacion, Transportista.nombre} */
@Override
public int compare(SeguimientoSeccion o1, SeguimientoSeccion o2) 
{
    int result;
    final Transportista t1, t2;
    if (   0 != (result = o1.getYear().compareTo(o2.getYear()))
        || 0 != (result = o1.getMonth().compareTo(o2.getMonth()))
        || 0 != (result = nullsLast(o1.getFijacion(),
                                    o2.getFijacion()))
        || 0 != (result = nullsLast(t1 = o1.getTransportista(),
                                    t2 = o2.getTransportista())))
        return result;
    return nullsLast(t1.getNombre(), t2.getNombre());
}

(null handling of nombres differs from the question ever so slightly.)

🌐
How to do in Java
howtodoinjava.com › home › collections framework › java comparator interface
Java Comparator Interface (with Examples) - HowToDoInJava
January 4, 2022 - Custom ordering of elements is imposed by implementing Comparator.compare() method in the objects. ... Java Comparator interface is used to sort an array or List of objects based on custom sort order.
🌐
W3Schools
w3schools.com › java › java_advanced_sorting.asp
Java Advanced Sorting (Comparator and Comparable)
For example, if you have a list of cars you might want to sort them by year, the rule could be that cars with an earlier year go first. The Comparator and Comparable interfaces allow you to specify what rule is used to sort objects.
🌐
DEV Community
dev.to › sohailshah › different-ways-to-use-comparator-interface-in-java-4mgj
Different Ways To Use Comparator Interface in Java - DEV Community
July 15, 2023 - One way to use the Comparator interface is by creating a separate class that implements the Comparator interface. This class will provide the logic for comparing objects based on specific criteria.