gpt4 book ai didi

java - 枚举、接口(interface)和 (Java 8) lambdas : code compiles but fails at runtime; is this expected?

转载 作者:IT老高 更新时间:2023-10-28 20:47:24 26 4
gpt4 key购买 nike

JDK 是 Oracle 的 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);
}
}

此代码编译;但它在运行时失败:

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

在代码中修复它很“容易”;在 main 方法中,您只需:

// Note the <X>
Stream.<X>of(E1.INSTANCE, E2.INSTANCE).forEach(X::x);

编辑实际上还有第二种方法,正如接受的答案中提到的那样...用 lambda 替换方法引用:

Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(x -> x.x());

所以,嗯。这里会发生什么?为什么初始代码首先编译?我希望编译器会注意到方法引用不在任何东西上 Enum<?>但在 X ,但没有……

我错过了什么?这是编译器中的错误吗?是我的误会?

最佳答案

您似乎点击了JDK-8141508 , 这确实是 javac 的错误在处理交集类型和方法引用时。它计划在 Java 9 中修复。

引用 a mail from Remi Forax :

javac has trouble with intersection type that are target type of a lambda and method reference, Usually when there is an intersection type, javac substitute it by the first type of the intersection type and add cast when necessary.

Let suppose we have this code,

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());
}
}

Currently, javac generates a method reference on J::foo with an invokedynamic that takes an I as parameter, hence it fails at runtime. javac should de-sugar t::foo into a lambda that take an I and then add a cast to J like for a call to a method of an intersection type.

So the workaround is to use a lambda instead,

Runnable r = t -> t.foo();

I've already seen this bug somewhere but was not able to find a corresponding bug report in the database :(

在您的代码中,Stream.of(E1.INSTANCE, E2.INSTANCE) 创建的流是 Stream<Enum<?>&Foo.X> 类型,它结合了 bug 的所有元素:相交类型和方法引用。

如 Remi Forax 所述,解决方法是:

Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(x -> x.x());

即使用显式 lambda 表达式而不是方法引用。

关于java - 枚举、接口(interface)和 (Java 8) lambdas : code compiles but fails at runtime; is this expected?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33925551/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com