At first glance a lambda looks like a short hand version of an anonymous inner class. But they are not. This post covers the differences between lambda’s and AIC’s
The key to the lambda implementation is the InvokeDynamic instruction introduced in Java 7. This allows dynamic languages to bind to symbol at runtime.
A lambda works like this –
Doesnt access fields outside its body
public class NonCapturingLambda { public static void main(String[] args) { Runnable nonCapturingLambda = () -> System.out.println("NonCapturingLambda"); nonCapturingLambda.run(); } }
If we decode the class file using the cfr decompiler, we see the –
java -jar cfr_0_119.jar NonCapturingLambda --decodelambdas false /* * Decompiled with CFR 0_119. */ import java.io.PrintStream; import java.lang.invoke.LambdaMetafactory; public class NonCapturingLambda { public static void main(String[] args) { Runnable nonCapturingLambda = (Runnable)LambdaMetafactory.metafactory(null, null, null, ()V, lambda$0(), ()V)(); nonCapturingLambda.run(); } private static /* synthetic */ void lambda$0() { System.out.println("NonCapturingLambda"); } }
Accesses final or effectively final fields outside its body –
public class CapturingLambda { public static void main(String[] args) { String effectivelyFinal = "effectivelyFinal"; Runnable capturingLambda = () -> System.out.println("capturingLambda " + effectivelyFinal); capturingLambda.run(); } }
This decompiles to –
java -jar cfr_0_119.jar CapturingLambda --decodelambdas false /* * Decompiled with CFR 0_119. */ import java.io.PrintStream; import java.lang.invoke.LambdaMetafactory; public class CapturingLambda { public static void main(String[] args) { String effectivelyFinal = "effectivelyFinal"; Runnable capturingLambda = (Runnable)LambdaMetafactory.metafactory(null, null, null, ()V, lambda$0(java.lang.String ), ()V)((String)effectivelyFinal); capturingLambda.run(); } private static /* synthetic */ void lambda$0(String string) { System.out.println("capturingLambda " + string); } }
The interesting part is the lambda$0 method signature has gone from empty to taking a parameter String
https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html