Java BootstrapMethodError由使用MethodHandle::invokeExact作为方法引用引起的LambdaConversionException引起

Java 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

我试图检查是否可以使用MethodHandle::invoke或MethodHandle::invokeExact作为接受MethodHandle并返回泛化输出的函数接口的方法引用

(我知道invoke和invokeExact是签名多态的,因此在invokeExact中使用了元工厂调用。但是,我想知道编译器是否能够省去我为派生合适版本的invoke/invokeExact所必须做的事情。)

invoke.InvokeExact0

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