I was looking through Java source code for the Map
interface and ran into this little snippet of code:
/**
* Returns a comparator that compares {@link Map.Entry} in natural order on value.
*
* <p>The returned comparator is serializable and throws {@link
* NullPointerException} when comparing an entry with null values.
*
* @param <K> the type of the map keys
* @param <V> the {@link Comparable} type of the map values
* @return a comparator that compares {@link Map.Entry} in natural order on value.
* @see Comparable
* @since 1.8
*/
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
From the method declaration I get that this is a generic method that returns a Comparator of a type that is either inferred from the map entries passed to it or explicitly provided in the method.
What's really throwing me off is the return value. It appears that the lambda expression
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
is explicitly cast to a Comparator<Map.Entry<K, V>>
. Is this right?
I also noticed that the apparent cast includes & Serializable
. I've never seen an interface combined with a class in a cast before, but it looks like the following valid in the compiler:
((SubClass & AnInterface) anObject).interfaceMethod();
Although the following doesn't work:
public class Foo {
public static void main(String[] args) {
Object o = new Foo() {
public void bar() {
System.out.println("nope");
}
};
((Foo & Bar) o).bar();
}
}
interface Bar {
public void bar();
}
So, two questions:
How does adding an interface to a cast supposed to work? Does this just enforce the return type of an interface's method?
Can you cast a Lambda expression to a
Comparator
? What else can they be cast as? Or is a lambda expression essentially just aComparator
? Can someone clarify all of this?