Well, lambda expressions are allocated to methods at compile time and until they capture this (don't have access to non- static elements), these methods will be static . The tricky part is moving on to these methods, since there is no controlled connection between the instance of the functional interface and its target method.
To illustrate this, here is the simplest case:
public class LambdaToMethod { public static void legacyCaller(Object arg, Method m) { System.out.println("calling Method \""+m.getName()+"\" reflectively"); try { m.invoke(null, arg); } catch(ReflectiveOperationException ex) { ex.printStackTrace(); } } public static void main(String[] args) throws URISyntaxException { Consumer<String> consumer=s -> System.out.println("lambda called with "+s); for(Method m: LambdaToMethod.class.getDeclaredMethods()) if(m.isSynthetic() && m.getName().contains("lambda")) { legacyCaller("a string", m); break; } } }
This works smoothly since there is only one lambda expression and therefore one candidate method. The name of this method is compiler specific and may contain some serial numbers or hash codes, etc.
In kludge, you need to make a serializable lambda expression and check its serialized form:
static Method lambdaToMethod(Serializable lambda) { for(Class<?> cl=lambda.getClass(); cl!=null; cl=cl.getSuperclass()) try { Method m=cl.getDeclaredMethod("writeReplace"); m.setAccessible(true); try { SerializedLambda sl=(SerializedLambda)m.invoke(lambda); return LambdaToMethod.class.getDeclaredMethod(sl.getImplMethodName(), MethodType.fromMethodDescriptorString(sl.getImplMethodSignature(), LambdaToMethod.class.getClassLoader()).parameterArray()); } catch(ReflectiveOperationException ex) { throw new RuntimeException(ex); } } catch(NoSuchMethodException ex){} throw new AssertionError(); } public static void main(String[] args) { legacyCaller("a string", lambdaToMethod((Consumer<String>&Serializable) s -> System.out.println("first lambda called with "+s))); legacyCaller("a string", lambdaToMethod((Consumer<String>&Serializable) s -> System.out.println("second lambda called with "+s))); }
It works, however, serializable lambdas come at a high price.
The simplest solution would be to add an annotation to the parameter of the lambda expression, which will be found during iteration by methods, however, at present, javac does not save the annotation properly, see also this question about this topic.
But you can also consider creating regular static methods that contain code instead of a lambda expression. Getting the Method object for a method is straightforward, and you can still create an instance of the functional interface from them using method references ...