In JDK 8, I can use reflection to call a method with a FunctionalInterface parameter, passing a Lambda expression. For instance, this works.
import java.util.function.IntPredicate;
import java.lang.reflect.Method;
public class LambdaReflect {
public static void main(String args[]) {
System.out.println(test(x->true));
// Now do this in reflection
Class<LambdaReflect> thisC = LambdaReflect.class;
Method meths[] = thisC.getDeclaredMethods();
Method m = meths[1]; // test method
try {
IntPredicate lamb = x->true;
boolean result = (Boolean) m.invoke(null, lamb);
System.out.println(result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static boolean test(IntPredicate func) {
return func.test(1);
}
}
However, if the parameter type is only known at runtime, how can I pass a lambda expression to the method? In other words, if I don't know at compile time the argument type of the method, but only know that it is a functional interface, can I use reflection to call it with a lambda expression?
You can’t create a lambda expression without knowing the target type at compile-time. But you can put the lambda’s code into a method and create a method reference to this method. This is similar to how lambda expressions are compiled. The difference is that the functional interface implementation is created explicitly using reflective code:
import java.lang.invoke.*;
import java.util.function.IntPredicate;
import java.lang.reflect.Method;
public class LambdaReflect {
public static void main(String args[]) {
try {
for(Method m: LambdaReflect.class.getDeclaredMethods()) {
if(!m.getName().equals("test")) continue;
// we don’t know the interface at compile-time:
Class<?> funcInterface=m.getParameterTypes()[0];
// but we have to know the signature to provide implementation code:
MethodType type=MethodType.methodType(boolean.class, int.class);
MethodHandles.Lookup l=MethodHandles.lookup();
MethodHandle target=l.findStatic(LambdaReflect.class, "lambda", type);
Object lambda=LambdaMetafactory.metafactory(l, "test",
MethodType.methodType(funcInterface), type, target, type)
.getTarget().invoke();
boolean result = (Boolean) m.invoke(null, lambda);
System.out.println(result);
break;
}
} catch (Throwable ex) {
ex.printStackTrace();
}
}
private static boolean lambda(int x) { return true; }
public static boolean test(IntPredicate func) {
return func.test(1);
}
}
If you want to implement arbitrary functional signatures (which implies that the implementation is rather trivial, not depending on the unknown parameters), you can use MethodHandleProxies
. The difference is that the MethodHandle
doesn’t need to be direct then, i.e. doesn’t need to represent a real method. So you can create a handle invariably returning a constant and use dropArguments
to insert additional formal parameters until you have a handle with the right functional signature which you can pass to asInterfaceInstance
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With