Jesus Zavarce
Jesus Zavarce

Reputation: 1759

How a Comparator is created from method reference?

I'm learning about lambda expressions. I don't understand how a comparator is returned from method reference.

I want to sort a list of persons by age.

To do that, I have a method to find the age difference:

public int ageDifference(final Person other) {
    return age - other.age;
}

The sorted method needs as parameter a Comparator

Stream<T> sorted(Comparator<? super T> comparator);

My lambda expression is:

people.stream()
.sorted(Person::ageDifference)
.collect(toList());

How Person::ageDifference is trasformed in a Comparator<Person>?

My complete example:

public class Person {

private final String name;
private final int age;

public Person(final String theName, final int theAge) {
    name = theName;
    age = theAge;
}

public String getName() {
    return name;
}

public int getAge() {
    return age;
}

public int ageDifference(final Person other) {
    return age - other.age;
}

public String toString() {
    return String.format("%s - %d", name, age);
}

public static void main (String args[] ){
    final List<Person> people = Arrays.asList(
            new Person("John", 10),
            new Person("Greg", 30),
            new Person("Sara", 20),
            new Person("Jane", 15));

    List<Person> ascendingAge =
            people.stream()
                    .sorted(Person::ageDifference)
                    .collect(toList());

    System.out.println(ascendingAge);
}
}

Output: [John - 10, Jane - 15, Sara - 20, Greg - 30]

Upvotes: 0

Views: 280

Answers (1)

Sweeper
Sweeper

Reputation: 272905

I guess your main confusion is this:

Comparator<T> represents a method that takes two parameters of type T and returns a int. My ageDifference method accepts only one Person parameter. How can that become a Comparator<Person>?

Note that ageDifference is an instance method. To call it, not only do you need the parameters, you also need an instance of Person. In this case, you need 2 Persons to call the method - one on which you call ageDifference, and the other one you pass as a parameter:

me.ageDifference(someoneElse)
^                      ^
|                      |
        Two people!

Isn't this just like a static method that accepts two parameters?

Therefore, Java is smart enough to know that you need two people to call Person::ageDifference, so the method reference is treated as having two parameters.

In general, an instance method of a class T accepting parameters P1, P2 ... Pn and returning type R can be treated as a static method accepting parameters T, P1, P2 ... Pn and returning R.

Upvotes: 5

Related Questions