Why does Java 8's Comparator.comparing() cast the return value to Serializable?
Asked Answered
R

2

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.

Responsiveness answered 6/1, 2017 at 6:15 Comment(2)
Possible duplicate of How to serialize a lambda?Gathers
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.Gathers
R
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.

Rupe answered 6/1, 2017 at 6:23 Comment(4)
internal class used by Java to implement the lambda <- Deep!Responsiveness
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.Stoltz
@Stoltz 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.Rupe
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!Stoltz
T
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.

Toluca answered 10/7, 2022 at 16:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.