The lambdas are created by the JRE and the way they are created is controlled by the JRE and might vary between different JRE vendors and might change in future versions.
If you want to have fun you can create a lambda at runtime which has no corresponding information within the class file:
import java.lang.invoke.*;
public class ManualLambda {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup me=MethodHandles.lookup();
MethodType t=MethodType.methodType(void.class);
MethodType rt=MethodType.methodType(Runnable.class);
CallSite site = LambdaMetafactory.metafactory(
me, "run", rt, t, me.findStatic(ManualLambda.class, "sayHello", t), t);
MethodHandle factory=site.getTarget();
Runnable r=(Runnable)factory.invoke();
System.out.println("created lambda: "+r);
r.run();
}
private static void sayHello() {
System.out.println("hello world");
}
}
The code above retraces what happens when a lambda is created. But for compile-time (“real”) lambda expressions the entire thing is triggered by a single invokedynamic
byte code instruction. The LambdaMetafactory.metafactory(…)
method is the bootstrap method which is called when the invokedynamic
instruction is executed the first time. The returned CallSite
object is permanently associated with the invokedynamic
instruction. If the CallSite
is a ConstantCallSite
and its MethodHandle
returns the same lambda object on every execution, the invokedynamic
instruction will “produce” the same lambda instance forever.