I am aware that a similar question has been asking about this topic here
To motivate why I am asking this, I was looking at different ways to write a stream pipeline to better understand what was going on, for instance:
Note: in the below code, the people variable is a List consisting of Person objects with a String name and int age as fields.
// 1. using minBy and just method reference
System.out.println(people.stream()
.collect(minBy(comparing(Person::getAge))));
// 2. Alternate way by using comparing to construct the Comparator object
System.out.println(people.stream()
.collect(minBy(comparing(person -> {
// System.out.println(person.getName() + " " + person.getAge());
return person.getAge();
}))));
// 3. Breaking down the function even further to try to understand:
System.out.println(people.stream()
.collect(minBy(new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
if (p1.getAge() > p2.getAge()) {
return 1;
} else if (p1.getAge() < p2.getAge()) {
return -1;
} else {
return 0;
}
}
})));
All three of these print the same Person object when I tested them.
The question I have is about the second way of writing it, which involves the comparing function. I've looked in the source code in the Comparator class and found:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
I only understand parts of this code. For instance, I see that keyExtractor is the lambda function that we passed into the comparing method, and that it is using this to extract some integer to order the objects with.
The other things I do not fully grasp are:
(1) The method signature - what is the meaning of the generic types before the return type? Are they just a way to ensure consistency of the types used in the method?
Am I able to put more than two types in the angle brackets like <A, B, C, D>?
(2) What does
(Comparator<T> & Serializable)
mean here?
Is it a cast to the lambda function that's being returned (Presumably this lambda is overriding the compare method)? And if it is a cast, what is the meaning of the "& Serializable" if we just want a Comparator to be returned?