8

From JDK8's Comparator.java:

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));
}

Notice the return statement is prefixed with an interesting cast: (Comparator<T> & Serializable)

I am already aware of and (I think) understand:

  • the & operator in generic type restrictions (and can infer its purpose here),
  • the Serializable interface.

However, used together in the cast is baffling to me.

What is the purpose of & Serializable if the return type does not require it?

I do not understand the intent.

Follow-up to dupe/close requests: This question How to serialize a lambda? does not answer question. My question specifically notes the return type has no mention of Serializable, thus the source of my confusion.

Community
  • 1
  • 1
kevinarpe
  • 20,319
  • 26
  • 127
  • 154
  • Possible duplicate of [How to serialize a lambda?](http://stackoverflow.com/questions/22807912/how-to-serialize-a-lambda) – shmosel Jan 06 '17 at 06:15
  • 1
    The return type isn't the issue. Casting it to `Serializable` *makes it serializable*. This method casts to allow callers to serialize the result if they so choose. – shmosel Jan 06 '17 at 06:23

2 Answers2

10

The javadoc of Comparator.comparing() says:

The returned comparator is serializable if the specified function is also serializable.

The cast ensures that the internal class used by Java to implement the lambda will implements Serializable.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • `internal class used by Java to implement the lambda` <- Deep! – kevinarpe Jan 06 '17 at 06:23
  • 2
    Thanks for your clarification however I'm still a little confused by the presence of this cast. Why is JDK library code taking on the responsibility of ensuring a characteristic of the generated lambda class? If generating ```Serializable``` lambda classes is required by spec, this cast should never be needed. Conversely, if it is not required by spec then this cast might fail for certain implementations. – mouselabs Jan 15 '20 at 19:50
  • 2
    @mouselabs The use of the word "if" in the quoted text makes it "not *required* by spec". The cast makes the lambda expression itself serializable, which means that *if* the `keyExtractor` object is serializable, then so is the returned `Comparator`, i.e. it ensures that serialization is *supported*. – Andreas Jan 15 '20 at 23:50
  • 1
    Ah...so the presence of the cast actually drives that aspect of the generated lambda class. You did say this initially I just didn't get it. I appreciate your excellent clarification. Thanks! – mouselabs Jan 17 '20 at 06:34
0

First, (Comparator<T> & Serializable) makes the lambda implements Serializable. It does not hurt to add the interface. However if not added, the comparing would return something that is not serializable even if the specified function is serializable, which is problematic.

Second, if the specified function is not serializable while the return the lambda is serializable, when you actually serialize it, it will fail as when Java serializes the lambda function itself, it will check whether the specified function is also serializable.

This could be tested by ObjectOutputStream and ObjectInputStream which implement Java's serialization and deserialization.

flyingfishcattle
  • 1,817
  • 3
  • 14
  • 25