recently I stumbled over the following code in the Java Comparator class:
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)); }
What’s confusing me is the (Comparator<T> & Serializable)
part. Since the method only returns a Comparator I don’t see the use in casting to Serializable. I also don’t see the reason to ever cast anything this way, or am I missing something?
It seems to me that if I wanted to cast an Object to multiple possible types, I could just introduce another generic type like this:
public static <T, U extends Comparable<? super U>, V extends Comparator<T> & Serializable> V comparing(Function<? super T, ? extends U> keyExtractor) { Objects.requireNonNull(keyExtractor); return (V) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); }
This way the returned value could be assigned to both Comparator or Serializable variables.
The only other reason I could think of, is to use that cast as some kind of typecheck to see if the lambda expression actually returns a Serializable.
If any of you have experience with this kind of cast or an idea what casting like this could accomplish, any help would be appreciated.
Advertisement
Answer
The weird thing about this kind of cast is that it’s different from all other casts in Java: If you “cast” a lambda expression like this in Java the lambda will actually implement Serializable
(i.e. this doesn’t just change the type the compiler knows about, but actually changes what types the object implements!)
What the cast does in this case is define a target type for the lambda expression, that it will match. The target type in this case is the intersection of Comparator<T>
and Serializable
, meaning the lambda instance at runtime will implement both of those interfaces.