将从文件中的方法转换为Lambda表达式

huangapple go评论85阅读模式
英文:

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

huangapple
  • 本文由 发表于 2020年9月15日 21:28:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63902925.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定