So I have a interface that extends BiConsumer
.
@FunctionalInterface
public interface MyActionWithParameters<E, P> extends BiConsumer<Selection<E>, P> {
@Override
default MyActionWithParameters<E, P> andThen(BiConsumer<? super Selection<E>, ? super P> after) {
var newAction = BiConsumer.super.andThen(after);
return newAction::accept;
}
}
This works.
But if I try to return (MyActionWithParameters<>) BiConsumer.super.andThen(after);
, I get a class cast exception.
Why is that? Why can I cast newAction::accept
(i.e. a new BiConsumer
) but not the BiConsumer
itself? I have a feeling the answer should be pretty obvious, but I just don't see it.
EDIT: full error
Caused by: java.lang.ClassCastException: class java.util.function.BiConsumer$$Lambda$2165/0x0000000840d10840 cannot be cast to class blah.blah.blah.MyFoo$MyActionWithParameters (java.util.function.BiConsumer$$Lambda$2165/0x0000000840d10840 is in module java.base of loader 'bootstrap'; blah.blah.blah.MyFoo$MyActionWithParameters is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @739fc679)
The reason why casting does not work is because whatever BiConsumer.andThen
returns, it does not implement MyActionWithParameters
. How on earth is BiConsumer
, a JDK interface, supposed to know about your own custom interface? :-)
But using a method reference works, because by using a method reference, the type of object that super.andThen
returns, aka newAction
, no longer matters. What matters is the method - accept
. Does accept
have a compatible signature to satisfy the functional interface of MyActionWithParameters
? Yes it does, so it works.