fge*_*fge 21 java type-inference java-8
JDK是甲骨文的JDK 1.8u65,但问题是"低至"1.8u25.
这是完整的SSCCE:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译; 但它在运行时失败:
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
Run Code Online (Sandbox Code Playgroud)
在代码中修复它是"容易的"; 在主要方法中,您只需:
// Note the <X>
Stream.<X>of(E1.INSTANCE, E2.INSTANCE).forEach(X::x);
Run Code Online (Sandbox Code Playgroud)
编辑实际上有第二种方法,如接受的答案中所述......用lambda替换方法引用:
Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(x -> x.x());
Run Code Online (Sandbox Code Playgroud)
所以,呃.这里发生了什么?为什么初始代码首先编译?我原本期望编译器注意到方法引用不是在任何东西Enum<?>上X,而是在......
我错过了什么?这是编译器中的错误吗?对我的误解?
Tun*_*aki 19
看来你已经遇到了JDK-8141508,这确实是javac处理交集类型和方法引用时的错误.它计划在Java 9中修复.
javac与作为lambda的目标类型和方法引用的交集类型有问题.通常当存在交集类型时,javac用交集类型的第一种类型替换它,并在必要时添加cast.
假设我们有这个代码,
Run Code Online (Sandbox Code Playgroud)public class Intersection { interface I { } interface J { void foo(); } static <T extends I & J> void bar(T t) { Runnable r = t::foo; } public static void main(String[] args) { class A implements I, J { public void foo() {} } bar(new A()); } }目前,javac使用一个以I为参数的invokedynamic在J :: foo上生成方法引用,因此它在运行时失败.javac应该将t :: foo解压缩为一个带有I的lambda,然后向J添加一个强制转换,就像调用一个交集类型的方法一样.
所以解决方法是使用lambda代替,
Run Code Online (Sandbox Code Playgroud)Runnable r = t -> t.foo();我已经在某个地方看到过这个错误,但是无法在数据库中找到相应的错误报告:(
在您的代码中,由Stream.of(E1.INSTANCE, E2.INSTANCE)类型创建的Stream Stream<Enum<?>&Foo.X>,它结合了bug的所有元素:交叉类型和方法引用.
如Remi Forax所述,解决方法是:
Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(x -> x.x());
Run Code Online (Sandbox Code Playgroud)
即使用显式的lambda表达式而不是方法引用.
| 归档时间: |
|
| 查看次数: |
1303 次 |
| 最近记录: |