java以编程方式创建Java8函数引用
只是一个理论问题,我目前没有实际的用例
假设一些my API接受函数引用作为参数,我希望通过“::”语法直接从代码中输入它,或者通过反射收集匹配的函数,存储在一些映射中并有条件地调用
可以通过编程将method
转换为Consumer<String>
Map<String, Consumer<String>> consumers = new HashMap<>();
consumers.put("println", System.out::println);
Method method = PrintStream.class.getMethod("println", String.class);
consumers.put("println", makeFunctionReference(method));
...
myapi.feedInto(consumers.get(someInput.getConsumerId()));
更新:
虽然对当前提供的答案中的解决方案不满意,但在得到关于LambdaMetaFactory
的提示后,我尝试编译这段代码
public class TestImpl {
public static void FnForString(String arg) {}
}
public class Test {
void test() {
List<String> strings = new ArrayList<>();
Consumer<String> stringConsumer = TestImpl::FnForString;
strings.stream().forEach(stringConsumer);
strings.stream().forEach(TestImpl::FnForString);
stringConsumer.accept("test");
}
}
在向CFR反编译器中只提供了测试类之后,我得到了以下结果:
public class Test {
void test() {
ArrayList strings = new ArrayList();
Consumer<String> stringConsumer =
(Consumer<String>)LambdaMetafactory.metafactory(
null, null, null,
(Ljava/lang/Object;)V,
FnForString(java.lang.String),
(Ljava/lang/String;)V)();
strings.stream().forEach(stringConsumer);
strings.stream().forEach(
(Consumer<String>)LambdaMetafactory.metafactory(
null, null, null,
(Ljava/lang/Object;)V,
FnForString(java.lang.String ),
(Ljava/lang/String;)V)());
stringConsumer.accept("test");
}
}
由此我看到:
- 这在某种程度上是有可能以“一行”的方式实现的
- 不需要异常处理
- 我不知道反编译器输出中的
(Ljava/lang/Object;)V
(和其他)是什么。它应该与metafactory()参数中的MethodType
匹配。此外,反编译器中的任何一个都“吃/藏”了一些东西,但现在似乎在获取函数引用的过程中调用了一些方法李> - (offtop)即使在编译代码中获得函数引用,也至少需要一次函数调用——一般来说,在性能关键的代码中,这可能不是不可察觉的廉价操作李>
而且。。。通过提供Test和TestImpl类,CFR重建了与我编译的完全相同的代码
共 (0) 个答案