Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a Java 8 Lambda Expression Compiled to? [duplicate]

Tags:

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} } 
like image 934
ams Avatar asked Feb 18 '14 15:02

ams


People also ask

What is the lambda expression in Java 8?

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.

What do you get if you compile a lambda in Java?

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.

What happens with lambda after compile time?

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.

How do you reuse lambda expression?

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.


1 Answers

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:

  • How will Java lambda functions be compiled?
like image 64
Sotirios Delimanolis Avatar answered Dec 10 '22 07:12

Sotirios Delimanolis