Reputation: 5
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)
Upvotes: 0
Views: 270
Reputation: 15163
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();
Upvotes: 1