英文:
Transform Method from file into LambdaExpresion
问题
我正试图将从文件中读取的方法转换为 lambda 表达式,以便我可以测量执行该方法所需的时间,忽略掉较慢的 Method.invoke(...) 函数。
我一直在尝试使用 LambdaMetafactory
来实现我的目标,但老实说,我已经阅读了很多关于如何做到这一点的问题和解释,以至于我甚至不知道我在做什么了。
假设参数和方法都构造得很好(这是棘手的部分),并且我必须动态处理涉及不同数量和类型参数的多个选项:
Object[] parameters = ...;
Method method = anotherClass.getMethod();
还有这个接口(对于命名我很抱歉,我以后会改):
@FunctionalInterface
interface LoadedMethod {
Object execute(Object[] params);
}
以下是尝试使用 lambda 执行方法的代码:
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(method);
CallSite callSite = LambdaMetafactory.metafactory(
lookup,
"execute",
MethodType.methodType(LoadedMethod.class),
mh.type(),
mh,
mh.type()
);
LoadedMethod loadedMethod = (LoadedMethod) callSite.getTarget().invokeExact();
System.out.println("OUTPUT: " + loadedMethod.execute(parameters)); // 错误发生在这里
我阅读了这个帖子,但我不理解我在做什么对和错。你能帮我吗?
【编辑】
当前的错误是:
java.lang.invoke.LambdaConversionException: 无法将参数数目不正确的静态方法 invokeStatic Example.myFunction:(int[],int,int)int 转换为 lambda 表达式;1 个已捕获参数,3 个函数接口方法参数,3 个实现参数
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:214)
at java.base/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:328)
at optimex.ObjectCallable.call(ObjectCallable.java:60)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
英文:
I'm trying to transform a Method (read from a file) into a lambda expression, so I can measure the time needed to execute that Method ignoring the slow Method.invoke(...) function.
I've been trying to accomplish my objective using LambdaMetafactory
, but to be honest I have read so many questions and explanations about how to do this that I don't even know what I'm doing anymore.
Assuming that parameters and the method are well constructed and (here's the tricky part) that I have to deal dynamically with multiple options involving different number and types of parameters:
Object[] parameters = ...;
Method metodin = anotherClass.getMethod();
And the interface (sorry for the name, I'll change it later):
@FunctionalInterface
interface loadedMethod {
Object execute(Object[] params);
}
Here's the code that tries to execute the method using a lambda:
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(metodin);
CallSite callsite = LambdaMetafactory.metafactory(
lookup,
"execute",
MethodType.methodType(loadedMethod.class),
mh.type(),
mh,
mh.type()
);
loadedMethod loadedMethod = (loadedMethod) callsite.getTarget().invokeExact();
System.out.println("OUTPUT: " + loadedMethod.execute(parameters)); //Error occurs here
I've read this post and I don't understand what I'm doing fine and wrong. Can you help me please?
[EDIT]
The current error is:
java.lang.invoke.LambdaConversionException: Incorrect number of parameters for static method invokeStatic Example.myFunction:(int[],int,int)int; 1 captured parameters, 3 functional interface method parameters, 3 implementation parameters
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:214)
at java.base/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:328)
at optimex.ObjectCallable.call(ObjectCallable.java:60)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
答案1
得分: 1
啊,是的。
你错误地调用了 metalambdafactory:
元 lambda 工厂的概念是它创建一个 lambda 工厂。
然后你使用该工厂来创建 lambda 的实际实例。
第一个 MethodType
用于工厂 - 在你的情况下,你说“捕获一个 Object[]
。
你可能不想捕获任何内容 - 所以正确的 MethodType 是 methodType(loadedMethod.class)
。
CallSite callsite = LambdaMetafactory.metafactory(
lookup,
"execute",
MethodType.methodType(loadedMethod.class),
mh.type(),
mh,
mh.type()
);
你使用 invokeWithArguments
调用生成的 MethodHandle。
由于工厂不需要额外的参数,你不应该传递它们:
loadedMethod loadedMethod = (loadedMethod) callsite.getTarget().invokeExact();
英文:
Ahh, yeah.
You call metalambdafactory wrong:
The concept of the meta lambda factory is that it creates a lambda factory.
You then use the factory to create the actual instance of the lambda.
The first MethodType
is for the factory - in your case you said "capture an Object[]
.
You probably don't want to capture anything - so the right MethodType is methodType(loadedMethod.class)
.
CallSite callsite = LambdaMetafactory.metafactory(
lookup,
"execute",
MethodType.methodType(loadedMethod.class),
mh.type(),
mh,
mh.type()
);
You invoke the resulting MethodHandle with invokeWithArguments
.
As the factory doesn't need the additional arguments, you should not pass them:
loadedMethod loadedMethod = (loadedMethod) callsite.getTarget().invokeExact();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论