JDK è Oracle JDK 1.8u65 ma il problema è stato riscontrato anche con "basso" come 1.8u25.Enum, interfacce e (Java 8) lambda: il codice viene compilato ma non riesce in fase di runtime; è previsto?
Ecco la SSCCE completo:
public final class Foo
{
private interface X
{
default void x()
{
}
}
private enum E1
implements X
{
INSTANCE,
;
}
private enum E2
implements X
{
INSTANCE,
;
}
public static void main(final String... args)
{
Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(X::x);
}
}
Questo codice viene compilato; ma non riesce in fase di esecuzione:
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
at com.github.fge.grappa.debugger.main.Foo.main(Foo.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Enum; not a subtype of implementation type interface com.github.fge.grappa.debugger.main.Foo$X
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 8 more
Il fissaggio nel codice è "facile"; nel metodo principale, devi solo:
// Note the <X>
Stream.<X>of(E1.INSTANCE, E2.INSTANCE).forEach(X::x);
EDIT V'è infatti un secondo modo, come menzionato nella risposta accettata ... sostituire il riferimento metodo con un lambda:
Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(x -> x.x());
Quindi, uh. Che succede qui? Perché il codice iniziale viene compilato in primo luogo? Mi sarei aspettato che il compilatore notasse che il riferimento al metodo non era su qualsiasi cosa Enum<?>
ma su X
, ma no ...
Cosa mi manca? È un bug nel compilatore? Un mio fraintendimento?
Forse un bug 'javac' correlato: [JDK-8141508] (https://bugs.openjdk.java.net/browse/JDK-8141508) anche se sembra che si tratti di tipi intersecanti. – Tunaki
@Tunaki interessante; Leggerò questo problema, forse è lo stesso ... – fge
È * un * tipo di intersezione. Il tipo inferito di 'Stream.of (E1.INSTANCE, E2.INSTANCE)' è 'Stream & Foo.X>', secondo la mia Eclipse. –
RealSkeptic