显式使用LambdaMetafactory [英] Explicit use of LambdaMetafactory
问题描述
我正在尝试显式使用LambdaMetafactory.metafactory,我无法理解为什么它仅适用于Runnable功能接口。例如,此代码执行预期的操作(它打印hello world):
I'm trying to explicitly use LambdaMetafactory.metafactory, I can't understand why it works only with the Runnable functional interface. For Example this code does what it is expected (it prints "hello world"):
public class MetafactoryTest {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(void.class);
MethodType invokedType = MethodType.methodType(Runnable.class);
CallSite site = LambdaMetafactory.metafactory(caller,
"run",
invokedType,
methodType,
caller.findStatic(MetafactoryTest.class, "print", methodType),
methodType);
MethodHandle factory = site.getTarget();
Runnable r = (Runnable) factory.invoke();
r.run();
}
private static void print() {
System.out.println("hello world");
}
}
当我尝试使用其他功能时出现问题界面,如供应商。以下代码不起作用:
The problem arise when I try to use a different functional interface, such as Supplier. The following code does not work:
public class MetafactoryTest {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class);
MethodType invokedType = MethodType.methodType(Supplier.class);
CallSite site = LambdaMetafactory.metafactory(caller,
"get",
invokedType,
methodType,
caller.findStatic(MetafactoryTest.class, "print", methodType),
methodType);
MethodHandle factory = site.getTarget();
Supplier<String> r = (Supplier<String>) factory.invoke();
System.out.println(r.get());
}
private static String print() {
return "hello world";
}
}
Exception in thread "main" java.lang.AbstractMethodError: metafactorytest.MetafactoryTest$$Lambda$1/258952499.get()Ljava/lang/Object;
at metafactorytest.MetafactoryTest.main(MetafactoryTest.java:29)
不应该两段代码以类似的方式工作,这是第二段代码中的问题?
Shouldn't the two snippet of code work in a similar way, which is the problem in the second snippet of code?
此外,以下代码应该是等效的,效果很好:
Moreover the following code, that should be equivalent, works well:
public class MetafactoryTest {
public static void main(String[] args) throws Throwable {
Supplier<String> r = (Supplier<String>) () -> print();
System.out.println(r.get());
}
private static String print() {
return "hello world";
}
}
编辑
避免更改方法返回类型的另一个解决方案是定义一个新的功能接口:
Another solution that avoids to change the method return type is to define a new functional interface:
public class MetafactoryTest {
@FunctionalInterface
public interface Test {
String getString();
}
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class);
MethodType invokedType = MethodType.methodType(Test.class);
CallSite site = LambdaMetafactory.metafactory(caller,
"getString",
invokedType,
methodType,
caller.findStatic(MetafactoryTest.class, "print", methodType),
methodType);
MethodHandle factory = site.getTarget();
Test r = (Test) factory.invoke();
System.out.println(r.getString());
}
private static String print() {
return "hello world";
}
推荐答案
Runnable和供应商之间的区别是供应商使用通用类型。
The difference between Runnable and Supplier is that Supplier uses a generic type.
在运行时供应商没有String get()方法,它有Object get()。但是您实现的方法返回一个String。您需要区分这两种类型。像这样:
At runtime Supplier doesn't have a String get() method, it has Object get(). But the method you implement returns a String. You need to distinguish between those 2 types. Like this:
public class MetafactoryTest {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(Object.class);
MethodType actualMethodType = MethodType.methodType(String.class);
MethodType invokedType = MethodType.methodType(Supplier.class);
CallSite site = LambdaMetafactory.metafactory(caller,
"get",
invokedType,
methodType,
caller.findStatic(MetafactoryTest.class, "print", actualMethodType),
methodType);
MethodHandle factory = site.getTarget();
Supplier<String> r = (Supplier<String>) factory.invoke();
System.out.println(r.get());
}
private static String print() {
return "hello world";
}
}
这篇关于显式使用LambdaMetafactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!