Consider the following Java 8 snippet.
public static void main(String[] args) { List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5); Consumer<Integer> consumer = x -> System.out.print(x); integers.forEach(consumer); }
What is Consumer<Integer> consumer = x -> System.out.print(x)
getting compiled to?
I understand that Lambdas are not implemented as anonymous inner classes. However Consumer<Integer>
is an interface therefore x -> System.out.print(x)
must be producing an object of some kind but it is not clear what kind of object is being produced.
Is there some new type of object in Java 8 to represent a lambda expression?
Update Here is the decompiled program the program was complied with the eclipse java 8 complier and the output below is from eclipse when you open a class file.
It looks like that the lambda expression is getting turned into a static method on the class that contains the lambda expression private static synthetic void lambda$0(java.lang.Integer x);
// Compiled from Example.java (version 1.8 : 52.0, super bit) public class Example { // Method descriptor #6 ()V // Stack: 1, Locals: 1 public Example(); 0 aload_0 [this] 1 invokespecial java.lang.Object() [8] 4 return Line numbers: [pc: 0, line: 7] Local variable table: [pc: 0, pc: 5] local: this index: 0 type: Example // Method descriptor #15 ([Ljava/lang/String;)V // Stack: 4, Locals: 3 public static void main(java.lang.String[] args); 0 iconst_5 1 anewarray java.lang.Integer [16] 4 dup 5 iconst_0 6 iconst_1 7 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18] 10 aastore 11 dup 12 iconst_1 13 iconst_2 14 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18] 17 aastore 18 dup 19 iconst_2 20 iconst_3 21 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18] 24 aastore 25 dup 26 iconst_3 27 iconst_4 28 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18] 31 aastore 32 dup 33 iconst_4 34 iconst_5 35 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18] 38 aastore 39 invokestatic java.util.Arrays.asList(java.lang.Object[]) : java.util.List [22] 42 astore_1 [integers] 43 invokedynamic 0 accept() : java.util.function.Consumer [31] 48 astore_2 [consumer] 49 getstatic java.lang.System.out : java.io.PrintStream [32] 52 aload_2 [consumer] 53 invokevirtual java.lang.Object.getClass() : java.lang.Class [38] 56 invokevirtual java.lang.Class.getCanonicalName() : java.lang.String [42] 59 invokevirtual java.io.PrintStream.println(java.lang.String) : void [48] 62 getstatic java.lang.System.out : java.io.PrintStream [32] 65 aload_2 [consumer] 66 invokevirtual java.lang.Object.getClass() : java.lang.Class [38] 69 invokevirtual java.lang.Class.getTypeName() : java.lang.String [54] 72 invokevirtual java.io.PrintStream.println(java.lang.String) : void [48] 75 aload_1 [integers] 76 aload_2 [consumer] 77 invokeinterface java.util.List.forEach(java.util.function.Consumer) : void [57] [nargs: 2] 82 return Line numbers: [pc: 0, line: 10] [pc: 43, line: 12] [pc: 49, line: 14] [pc: 62, line: 15] [pc: 75, line: 17] [pc: 82, line: 18] Local variable table: [pc: 0, pc: 83] local: args index: 0 type: java.lang.String[] [pc: 43, pc: 83] local: integers index: 1 type: java.util.List [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer Local variable type table: [pc: 43, pc: 83] local: integers index: 1 type: java.util.List<java.lang.Integer> [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer<java.lang.Integer> // Method descriptor #73 (Ljava/lang/Integer;)V // Stack: 2, Locals: 1 private static synthetic void lambda$0(java.lang.Integer x); 0 getstatic java.lang.System.out : java.io.PrintStream [32] 3 aload_0 [x] 4 invokevirtual java.io.PrintStream.print(java.lang.Object) : void [74] 7 return Line numbers: [pc: 0, line: 12] Local variable table: [pc: 0, pc: 8] local: x index: 0 type: java.lang.Integer Inner classes: [inner class info: #96 java/lang/invoke/MethodHandles$Lookup, outer class info: #98 java/lang/invoke/MethodHandles inner name: #100 Lookup, accessflags: 25 public static final] Bootstrap methods: 0 : # 89 arguments: {#90,#93,#94} }
Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.
The value of a lambda expression is a reference to an instance of a class with the following properties: The class implements the targeted functional interface and, if the target type is an intersection type, every other interface element of the intersection.
For Lambda expressions, the compiler doesn't translate them into something which is already understood by JVM. Lambda syntax that is written by the developer is desugared into JVM level instructions generated during compilation, which means the actual responsibility of constructing lambda is deferred to runtime.
One way I can reuse this lambda expression is if there is some interface/class which is a parent of all lambda expressions such that I can assign any lambda expression to a reference of such an interface/class.
The current draft of the Java 8 Language Specification states (chapter 15.27.4)
The value of a lambda expression is a reference to an instance of a class with the following properties:
- The class implements the targeted functional interface and, if the target type is an intersection type, every other interface element of the intersection.
- The class declares a method that overrides the functional interface supertype's abstract methods (and, potentially, some other methods of its superinterfaces).
- The method's parameter types, return type, and thrown types are given by the interface's function type.
- The method's body has the effect of evaluating the lambda body, if it is an expression, or of executing the lambda body, if it is a block; if a result is expected, it is returned from the method.
- The class overrides no other methods of the interface or interfaces mentioned above, except that it may override methods of the
Object
class.
Note that the JLS doesn't say anything about how the code should be compiled except that the byte code should support the specification above.
As such, the object returned by the lambda expression
x -> System.out.print(x);
will be an instance of a class that follows the above rules.
Given your comment that
consumer.getClass()
returns the following class
Example$$Lambda$1/1072591677
it seems that it is generating a proxy-like class specific for lambda expressions.
See here:
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