🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › Comparator.html
Comparator (Java Platform SE 8 )
October 20, 2025 - Java™ Platform Standard Ed. 8 ... This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. @FunctionalInterface public interface Comparator<T>
🌐
Baeldung
baeldung.com › home › java › guide to java comparator.comparing()
Guide to Java Comparator.comparing() | Baeldung
January 8, 2024 - A practical guide to the static functions and instance methods of the Comparable interface that were introduced in Java 8.
🌐
Mkyong
mkyong.com › home › java8 › java 8 lambda : comparator example
Java 8 Lambda : Comparator example - Mkyong.com
August 5, 2015 - In this example, we will show you how to use Java 8 Lambda expression to write a Comparator to sort a List.
🌐
Readthedocs
java8tips.readthedocs.io › en › stable › comparator.html
7. Comparator — Java 8 tips 1.0 documentation
A new utility class Comparators is bundled with jdk-8 to support natural ordered sorting and handling null values while sorting.
🌐
Javabrahman
javabrahman.com › java-8 › the-complete-java-8-comparator-tutorial-with-examples
The Complete Java 8 Comparator Tutorial with examples
Java 8's Comparator as an assignment target for LambdaExpressions Given the fact that its a functional interface, an instance of a Comparator can now be created in Java 8 with a lambda expression specifying its comparison logic. Take a look at the code snippet below - ... package ...
🌐
Readthedocs
java-8-tips.readthedocs.io › en › stable › comparator.html
7. Comparator — Java 8 tips 1.0 documentation
A new utility class Comparators is bundled with jdk-8 to support natural ordered sorting and handling null values while sorting.
🌐
Blogger
javarevisited.blogspot.com › 2023 › 04 › 7-examples-of-comparator-and-comparable.html
7 Examples of Comparator and Comparable in Java 8
Hello guys, you may know that Java ... and Comparable interfaces. The Comparator interface provides a way to compare two objects and sort them based on specific criteria....
🌐
Blogger
javarevisited.blogspot.com › 2021 › 09 › comparator-comparing-thenComparing-example-java-.html
Java 8 Comparator comparing() and thenComparing() Example - Tutorial
I like books, so I'll create a Book object with some fields to demonstrate how you can sort a list of books using Java 8 features like lambda expressions and method reference. ... public class Book implements Comparable < Book > { private String title; private String author; private int price; public Book(String title, String author, int price) { this.title = title; this.author = author; this.price = price; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getPrice() { return price; } public void setTitle(String title) { this.title = title; }
Find elsewhere
🌐
Java67
java67.com › 2019 › 06 › top-5-sorting-examples-of-comparator-and-comparable-in-java.html
6 Advanced Comparator and Comparable Examples in Java 8 | Java67
I like books, so I'll create a Book object with some fields to demonstrate how you can sort a list of book objects by single or multiple fields using Java 8 features. ... class Book implements Comparable<Book> { private String title; private String author; private int price; public Book(String title, String author, int price) { this.title = title; this.author = author; this.price = price; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getPrice() { return price; } public void setTitle(String title) { this.title = title; } public void setAuth
🌐
Medium
medium.com › @ganesh.shah › comparator-vs-comparable-java-8-940a83f53bd3
Comparator vs Comparable | Java 8 | by GANESH SHAH | Medium
March 8, 2024 - Comparator vs Comparable | Java 8 In Java, Comparator and Comparable are interfaces used for sorting objects, but they serve different purposes: Comparable Interface: The Comparable interface is …
🌐
Baeldung
baeldung.com › home › java › core java › comparator and comparable in java
Comparator and Comparable in Java | Baeldung
March 26, 2025 - If we want a different sorting ... Steven] Java 8 provides new ways of defining Comparators by using lambda expressions, and the comparing() static factory method....
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › java comparator with lambda
Java Comparator with Lambda (with Examples) - HowToDoInJava
February 6, 2023 - Learn to create a Comparator instance with lambda expressions, method references and chaining multiple comparators for complex comparisons.
🌐
Oracle
docs.oracle.com › javame › 8.0 › api › cldc › api › java › util › Comparator.html
Comparator (Java(TM) ME Connected Limited Device Configuration, Version 8 (JSR360 Final Release))
A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order.
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).

🌐
Praveer09
praveer09.github.io › technology › 2016 › 06 › 20 › writing-comparators-the-java8-way
Writing Comparators - The Java 8 Way
Java 8 introduced a few default methods and static factory methods on the Comparator interface using which developers can write Comparators in a declarative way. The Comparator interface combines the principles from Builder Pattern, Factory ...
Top answer
1 of 4
159

First, all the examples you say cause errors compile fine with the reference implementation (javac from JDK 8.) They also work fine in IntelliJ, so its quite possible the errors you're seeing are Eclipse-specific.

Your underlying question seems to be: "why does it stop working when I start chaining." The reason is, while lambda expressions and generic method invocations are poly expressions (their type is context-sensitive) when they appear as method parameters, when they appear instead as method receiver expressions, they are not.

When you say

Collections.sort(playlist1, comparing(p1 -> p1.getTitle()));

there is enough type information to solve for both the type argument of comparing() and the argument type p1. The comparing() call gets its target type from the signature of Collections.sort, so it is known comparing() must return a Comparator<Song>, and therefore p1 must be Song.

But when you start chaining:

Collections.sort(playlist1,
                 comparing(p1 -> p1.getTitle())
                     .thenComparing(p1 -> p1.getDuration())
                     .thenComparing(p1 -> p1.getArtist()));

now we've got a problem. We know that the compound expression comparing(...).thenComparing(...) has a target type of Comparator<Song>, but because the receiver expression for the chain, comparing(p -> p.getTitle()), is a generic method call, and we can't infer its type parameters from its other arguments, we're kind of out of luck. Since we don't know the type of this expression, we don't know that it has a thenComparing method, etc.

There are several ways to fix this, all of which involve injecting more type information so that the initial object in the chain can be properly typed. Here they are, in rough order of decreasing desirability and increasing intrusiveness:

  • Use an exact method reference (one with no overloads), like Song::getTitle. This then gives enough type information to infer the type variables for the comparing() call, and therefore give it a type, and therefore continue down the chain.
  • Use an explicit lambda (as you did in your example).
  • Provide a type witness for the comparing() call: Comparator.<Song, String>comparing(...).
  • Provide an explicit target type with a cast, by casting the receiver expression to Comparator<Song>.
2 of 4
29

The problem is type inferencing. Without adding a (Song s) to the first comparison, comparator.comparing doesn't know the type of the input so it defaults to Object.

You can fix this problem 1 of 3 ways:

  1. Use the new Java 8 method reference syntax

     Collections.sort(playlist,
                Comparator.comparing(Song::getTitle)
                .thenComparing(Song::getDuration)
                .thenComparing(Song::getArtist)
                );
    
  2. Pull out each comparison step into a local reference

      Comparator<Song> byName = (s1, s2) -> s1.getArtist().compareTo(s2.getArtist());
    
      Comparator<Song> byDuration = (s1, s2) -> Integer.compare(s1.getDuration(), s2.getDuration());
    
        Collections.sort(playlist,
                byName
                .thenComparing(byDuration)
                );
    

    EDIT

  3. Forcing the type returned by the Comparator (note you need both the input type and the comparison key type)

    sort(
      Comparator.<Song, String>comparing((s) -> s.getTitle())
                .thenComparing(p1 -> p1.getDuration())
                .thenComparing(p1 -> p1.getArtist())
                );
    

I think the "last" thenComparing syntax error is misleading you. It's actually a type problem with the whole chain, it's just the compiler only marking the end of the chain as a syntax error because that's when the final return type doesn't match I guess.

I'm not sure why List is doing a better inferencing job than Collection since it should do the same capture type but apparently not.

🌐
GitHub
gist.github.com › 721d9addf7dccc69847f5059e9f80cc7
Java 8 Comparator, sort y lambda · GitHub
Java 8 Comparator, sort y lambda. GitHub Gist: instantly share code, notes, and snippets.