This is a lambda:
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
This is a cast :
(Comparator<T> & Serializable)
This cast causes the lambda to be interpreted as being Comparator<T> & Serializable
.
The type Comparator<T> & Serializable
is an intersection type, which means Comparator<T>
and Serializable
at the same time. The use of intersection types is quite rare to see in Java, and so this is a feature of the language you will only see being applied in real code one time or another.
In this case, when using cast from one lambda to another type, the compiler type inference is going to be inferred as lambda type, the type pointed to in cast . That is, the part of the compiler that tries to guess the type of parameters and the return of the lambda will end up concluding that the return type is that intersection type. Since Comparator<T>
has only one abstract method, Serializable
has no abstract methods and both are interfaces, so this type is representable by a lambda.
The compiler will see this code as something more or less equivalent to this:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
class Temp implements Comparator<T>, Serializable {
@Override
public int compare(T c1, T c2) {
return keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
}
return new Temp();
}
The purpose of doing this is to allow an object that is performing a lambda to be also serializable, avoiding a java.io.NotSerializableException
occurrence in the case of the attempt to serialize some object that has in a of its non-% fields, the object returned by the transient
method.