Search code examples
javacastingjava-8type-boundsbounded-types

Strange Java cast syntax using &


(Actually, this question is not directly related to lambdas, but to casts using bounds, so the question marked as duplicate does not provide an answer to this question. You'll find the answer to my question here: How should I cast for Java generic with multiple bounds?)

Just recently, I took part in a SW craftsmanship meeting. In one of the discussed examples, I encountered kind of this cast, it seems to be valid Java since Java 8.

Object aTest = (String & CharSequence) "test";

My question: Can anybody tell me the idiom behind this and what it exactly can do for us? The presenter of the example couldn't explain it and I didn't find any mention (I don't even know a name for it).

I have to put another answer here, in addition to Oleksandr's, because this question was already marked as duplicate and thus is locked.

Meanwhile I was able to construct a (contrived) use case, just to make the idea clear.

Assume we have the generic method foo(), which is generic on its only parameter, and the type parameter has two upper bounds (against Comparable and Serializable):

public static <T extends Comparable & Serializable> void foo(T t) {
    System.out.println(t);
}

Further assume, we have a class AClass, which implements Comparable and Serializable

public class AClass implements Comparable, Serializable {
    @Override
    public int compareTo(Object other) {
        return 0;
    }
}

Further assume the contrived part, where we have an AClass object instance, which is assigned to a variable of type Object:

Object instance = new AClass();

If, in another place of the code, we want to pass instance to foo(), and we don't know the dynamic type of instance (which is AClass), we can use a special cast syntax to place a "contact lens" on instance to make the call work:

foo((Comparable & Serializable) instance);

Actually, the specialty is not in the cast syntax, but on how the type is specified. This type specification declares a so-called intersection type.


Solution

  • It's a cast operator that can contain a list of types:

    (ReferenceType {AdditionalBound}) Expression  =>  (String & CharSequence) "test";
    

    Where AdditionalBound is defined as:

    ... & InterfaceType
    

    I'm understanding this generally, but what about a use case?

    This question and the answers describe a real practical use case. For example, to make a lambda expression serializable, you can write:

    Consumer<String> consumer = (Consumer<String> & Serializable) System.out::println;
    

    (thanks to @assylias)