Java BootstrapMethodError由使用MethodHandle::invokeExact作为方法引用引起的LambdaConversionException引起
我试图检查是否可以使用MethodHandle::invoke或MethodHandle::invokeExact作为接受MethodHandle并返回泛化输出的函数接口的方法引用 (我知道invoke和invokeExact是签名多态的,因此在invokeExact中使用了元工厂调用。但是,我想知道编译器是否能够省去我为派生合适版本的invoke/invokeExact所必须做的事情。) invoke.InvokeExact0Java BootstrapMethodError由使用MethodHandle::invokeExact作为方法引用引起的LambdaConversionException引起,java,lambda,java-8,invokedynamic,methodhandle,Java,Lambda,Java 8,Invokedynamic,Methodhandle,我试图检查是否可以使用MethodHandle::invoke或MethodHandle::invokeExact作为接受MethodHandle并返回泛化输出的函数接口的方法引用 (我知道invoke和invokeExact是签名多态的,因此在invokeExact中使用了元工厂调用。但是,我想知道编译器是否能够省去我为派生合适版本的invoke/invokeExact所必须做的事情。) invoke.InvokeExact0 package invoke; import java.lang
package invoke;
import java.lang.invoke.MethodHandle;
import static java.lang.System.out;
import static java.lang.invoke.LambdaMetafactory.metafactory;
import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodType.methodType;
@FunctionalInterface
public interface InvokeExact0<OUTPUT> {
public OUTPUT invokeExact(MethodHandle methodHandle) throws Throwable;
public static <OUTPUT> InvokeExact0<OUTPUT> new_(InvokeExact0<OUTPUT> invokeExact) {
return invokeExact;
}
public static void main(String... arguments) throws Throwable {
out.println(
(InvokeExact0<String>) metafactory(
lookup(),
"invokeExact",
methodType(InvokeExact0.class),
methodType(
Object.class,
MethodHandle.class
),
lookup().findVirtual(
MethodHandle.class,
"invokeExact",
methodType(String.class)
),
methodType(
String.class,
MethodHandle.class
)
)
.getTarget()
.invokeExact()
);
out.println(InvokeExact0.new_(MethodHandle::invokeExact));
}
}
好消息是,元工厂方法能够合成一个工作的函数接口实例(如图所示:invoke.InvokeExact0$$Lambda$1)/1878246837@1be6f5c3).
坏消息是方法引用方法导致了LambdaConversionException,这反过来又导致了BootstrapMethodError
然后,我想问我应该如何解释LambdaConversionException中的错误细节,由于元工厂解决方案仍然存在。如果
MethodHandle.invokeExact
的方法句柄具有正确的签名,则手动调用元工厂的代码确实表明元工厂将完成其工作。调试发现,在第二种情况下,方法句柄有一个(MethodHandle,MethodHandle)对象
签名,它应该是(MethodHandle)对象
由于MethodHandle.invokeExact
允许任意签名(当然,它的第一个参数必须是MethodHandle
),这两个参数都可以创建,但metafactory拒绝该句柄,因为它与函数签名不匹配,因为范围中没有第二个方法句柄
这表示生成方法句柄常量的编译器中存在错误。通常,如果您有非反射代码,并且InvokeExact0.new(MethodHandle::invokeExact)
引用反射操作,但不执行反射操作,但得到运行时错误,则表明存在编译器错误
有一个简单的解决办法。当
InvokeExact0<Object> ie=MethodHandle::invokeExact;
InvokeExact0 ie=MethodHandle::invokeExact;
由于上述错误而失败
InvokeExact0<Object> ie=mh -> mh.invokeExact();
InvokeExact0 ie=mh->mh.invokeExact();
一切正常。只要您想要不同的返回类型,就需要一个lambda表达式来代替方法引用
InvokeExact0<String> ie=mh -> (String)mh.invokeExact();
InvokeExact0 ie=mh->(字符串)mh.invokeExact();
InvokeExact0<String> ie=mh -> (String)mh.invokeExact();