Are Java 8 lambdas compiled as inner classes, methods or something else? [duplicate]

Solution 1:

The expression itself, assuming you pass an actual lambda expression and not a method reference, is compiled as a separate, synthetic method. In addition to any formal arguments to the expected functional interface (e.g., a single String in the case of Consumer<String>), it will include arguments for any captured values.

At the code location where a lambda expression or method reference appears, an invokedynamic instruction is emitted. The first time this instruction is hit, a call is made into a bootstrap method on LambdaMetafactory. This bootstrap method will fix up an actual implementation of the target functional interface which delegates to the target method, and this is what gets returned. The target method is either the synthetic method representing the lambda body or whichever named method was provided using the :: operator. While a class that implements the functional interface is being created, the process is deferred; it does not happen at compile time.

Finally, the runtime patches the invokedynamic site with the bootstrap result1, which is effectively a constructor call to the generated delegate with any captured values passed in, including (possibly) an invocation target2. This alleviates the performance hit by removing the bootstrapping process for subsequent calls.


1 See java.lang.invoke end of chapter "timing of linkage", courtesy of @Holger.

2 In the case of a lambda which no captures, the invokedynamic instruction will usually resolve to a shared delegate instance that can be reused during subsequent calls, though this is an implementation detail.

Solution 2:

I asked myself the same question and found this video, a talk by Brian Goetz. It is very useful introduction to how lambdas are implemented in java.

Edit (summary): Watched it a while back, so this might not be completely correct. When the files are compiled, the compiler leaves a description of what the lambda should do. The JRE, then when running the code, will then decide how to implement the lambda. There are several options, inline, method reference, anonymous class. It will then use dynamic allocation to allocate the implementation.