How to compile jambda java functions?

Loop.times(5, () -> { System.out.println("looping"); }); 

Which ones could he efficiently compile?

 for(int i = 0; i < 5; i++) System.out.println("looping"); 

or something like

 new CallableInterfaceImpl(){ public void call(){ for(int i = 0; i < 5; i++) System.out.println("looping"); } }.call(); 

Otherwise, would it replace (like the built-in) or actually create an anonymous class?

+53
java lambda java-8
May 30 '13 at 3:01
source share
3 answers

VM decides how to implement lambda, not compiler.

See the Translation strategy section in Translating lambda expressions .

Instead of generating bytecode to create an object that implements a lambda expression (for example, calling a constructor for an inner class), we describe a recipe for building a lambda and delegate the actual construction to the runtime language. This recipe is encoded in static and dynamic argument lists of invokedynamic instructions.

for building from your example is the most efficient way in terms of simple compilation or performance (but the differences in performance are very small, according to the test results).

Addon :

I created and parsed two examples:

 for (String string: Arrays.asList("hello")) { System.out.println(string); } 

Disassembled bytecode, constants and other information:

 Classfile LambdaCode.class Last modified 30.05.2013; size 771 bytes MD5 checksum 79bf2821b5a14485934e5cebb60c99d6 Compiled from "LambdaCode.java" public class test.lambda.LambdaCode SourceFile: "LambdaCode.java" minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #11.#22 // java/lang/Object."<init>":()V #2 = Class #23 // java/lang/String #3 = String #24 // hello #4 = Methodref #25.#26 // java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; #5 = InterfaceMethodref #27.#28 // java/util/List.iterator:()Ljava/util/Iterator; #6 = InterfaceMethodref #29.#30 // java/util/Iterator.hasNext:()Z #7 = InterfaceMethodref #29.#31 // java/util/Iterator.next:()Ljava/lang/Object; #8 = Fieldref #32.#33 // java/lang/System.out:Ljava/io/PrintStream; #9 = Methodref #34.#35 // java/io/PrintStream.println:(Ljava/lang/String;)V #10 = Class #36 // test/lambda/LambdaCode #11 = Class #37 // java/lang/Object #12 = Utf8 <init> #13 = Utf8 ()V #14 = Utf8 Code #15 = Utf8 LineNumberTable #16 = Utf8 main #17 = Utf8 ([Ljava/lang/String;)V #18 = Utf8 StackMapTable #19 = Class #38 // java/util/Iterator #20 = Utf8 SourceFile #21 = Utf8 LambdaCode.java #22 = NameAndType #12:#13 // "<init>":()V #23 = Utf8 java/lang/String #24 = Utf8 hello #25 = Class #39 // java/util/Arrays #26 = NameAndType #40:#41 // asList:([Ljava/lang/Object;)Ljava/util/List; #27 = Class #42 // java/util/List #28 = NameAndType #43:#44 // iterator:()Ljava/util/Iterator; #29 = Class #38 // java/util/Iterator #30 = NameAndType #45:#46 // hasNext:()Z #31 = NameAndType #47:#48 // next:()Ljava/lang/Object; #32 = Class #49 // java/lang/System #33 = NameAndType #50:#51 // out:Ljava/io/PrintStream; #34 = Class #52 // java/io/PrintStream #35 = NameAndType #53:#54 // println:(Ljava/lang/String;)V #36 = Utf8 test/lambda/LambdaCode #37 = Utf8 java/lang/Object #38 = Utf8 java/util/Iterator #39 = Utf8 java/util/Arrays #40 = Utf8 asList #41 = Utf8 ([Ljava/lang/Object;)Ljava/util/List; #42 = Utf8 java/util/List #43 = Utf8 iterator #44 = Utf8 ()Ljava/util/Iterator; #45 = Utf8 hasNext #46 = Utf8 ()Z #47 = Utf8 next #48 = Utf8 ()Ljava/lang/Object; #49 = Utf8 java/lang/System #50 = Utf8 out #51 = Utf8 Ljava/io/PrintStream; #52 = Utf8 java/io/PrintStream #53 = Utf8 println #54 = Utf8 (Ljava/lang/String;)V { public test.lambda.LambdaCode(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 15: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=3, args_size=1 0: iconst_1 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String hello 8: aastore 9: invokestatic #4 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 12: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 17: astore_1 18: aload_1 19: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 24: ifeq 47 27: aload_1 28: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 33: checkcast #2 // class java/lang/String 36: astore_2 37: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 40: aload_2 41: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 44: goto 18 47: return LineNumberTable: line 35: 0 line 36: 37 line 37: 44 line 38: 47 StackMapTable: number_of_entries = 2 frame_type = 252 /* append */ offset_delta = 18 locals = [ class java/util/Iterator ] frame_type = 250 /* chop */ offset_delta = 28 } 

and

 Arrays.asList("hello").forEach(p -> {System.out.println(p);}); 

Disassembled bytecode, constants and other information:

 Classfile LambdaCode.class Last modified 30.05.2013; size 1262 bytes MD5 checksum 4804e0a37b73141d5791cc39d51d649c Compiled from "LambdaCode.java" public class test.lambda.LambdaCode SourceFile: "LambdaCode.java" InnerClasses: public static final #64= #63 of #70; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #27 invokestatic java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: #28 invokeinterface java/util/function/Consumer.accept:(Ljava/lang/Object;)V #29 invokestatic test/lambda/LambdaCode.lambda$0:(Ljava/lang/String;)V #30 (Ljava/lang/String;)V minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #10.#21 // java/lang/Object."<init>":()V #2 = Class #22 // java/lang/String #3 = String #23 // hello #4 = Methodref #24.#25 // java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; #5 = InvokeDynamic #0:#31 // #0:lambda$:()Ljava/util/function/Consumer; #6 = InterfaceMethodref #32.#33 // java/util/List.forEach:(Ljava/util/function/Consumer;)V #7 = Fieldref #34.#35 // java/lang/System.out:Ljava/io/PrintStream; #8 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/String;)V #9 = Class #38 // test/lambda/LambdaCode #10 = Class #39 // java/lang/Object #11 = Utf8 <init> #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 main #16 = Utf8 ([Ljava/lang/String;)V #17 = Utf8 lambda$0 #18 = Utf8 (Ljava/lang/String;)V #19 = Utf8 SourceFile #20 = Utf8 LambdaCode.java #21 = NameAndType #11:#12 // "<init>":()V #22 = Utf8 java/lang/String #23 = Utf8 hello #24 = Class #40 // java/util/Arrays #25 = NameAndType #41:#42 // asList:([Ljava/lang/Object;)Ljava/util/List; #26 = Utf8 BootstrapMethods #27 = MethodHandle #6:#43 // invokestatic java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #28 = MethodHandle #9:#44 // invokeinterface java/util/function/Consumer.accept:(Ljava/lang/Object;)V #29 = MethodHandle #6:#45 // invokestatic test/lambda/LambdaCode.lambda$0:(Ljava/lang/String;)V #30 = MethodType #18 // (Ljava/lang/String;)V #31 = NameAndType #46:#47 // lambda$:()Ljava/util/function/Consumer; #32 = Class #48 // java/util/List #33 = NameAndType #49:#50 // forEach:(Ljava/util/function/Consumer;)V #34 = Class #51 // java/lang/System #35 = NameAndType #52:#53 // out:Ljava/io/PrintStream; #36 = Class #54 // java/io/PrintStream #37 = NameAndType #55:#18 // println:(Ljava/lang/String;)V #38 = Utf8 test/lambda/LambdaCode #39 = Utf8 java/lang/Object #40 = Utf8 java/util/Arrays #41 = Utf8 asList #42 = Utf8 ([Ljava/lang/Object;)Ljava/util/List; #43 = Methodref #56.#57 // java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #44 = InterfaceMethodref #58.#59 // java/util/function/Consumer.accept:(Ljava/lang/Object;)V #45 = Methodref #9.#60 // test/lambda/LambdaCode.lambda$0:(Ljava/lang/String;)V #46 = Utf8 lambda$ #47 = Utf8 ()Ljava/util/function/Consumer; #48 = Utf8 java/util/List #49 = Utf8 forEach #50 = Utf8 (Ljava/util/function/Consumer;)V #51 = Utf8 java/lang/System #52 = Utf8 out #53 = Utf8 Ljava/io/PrintStream; #54 = Utf8 java/io/PrintStream #55 = Utf8 println #56 = Class #61 // java/lang/invoke/LambdaMetafactory #57 = NameAndType #62:#66 // metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #58 = Class #67 // java/util/function/Consumer #59 = NameAndType #68:#69 // accept:(Ljava/lang/Object;)V #60 = NameAndType #17:#18 // lambda$0:(Ljava/lang/String;)V #61 = Utf8 java/lang/invoke/LambdaMetafactory #62 = Utf8 metaFactory #63 = Class #71 // java/lang/invoke/MethodHandles$Lookup #64 = Utf8 Lookup #65 = Utf8 InnerClasses #66 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #67 = Utf8 java/util/function/Consumer #68 = Utf8 accept #69 = Utf8 (Ljava/lang/Object;)V #70 = Class #72 // java/lang/invoke/MethodHandles #71 = Utf8 java/lang/invoke/MethodHandles$Lookup #72 = Utf8 java/lang/invoke/MethodHandles { public test.lambda.LambdaCode(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 15: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: iconst_1 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String hello 8: aastore 9: invokestatic #4 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 12: invokedynamic #5, 0 // InvokeDynamic #0:lambda$:()Ljava/util/function/Consumer; 17: invokeinterface #6, 2 // InterfaceMethod java/util/List.forEach:(Ljava/util/function/Consumer;)V 22: return LineNumberTable: line 28: 0 line 38: 22 } 

The file generated by the compiler class is more complex and larger (771b versus 1262b) for the Lambda example.

+47
May 30 '13 at 5:59
source share

The lambda syntax written by the developer understands the JVM level instructions generated at compile time. therefore, the actual responsibility for constructing the lambda is transferred to runtime.

To make Java less compile-time and allow JVM languages ​​to link code at runtime, Java 7 introduced the new invokedynamic bytecode for the JVM and the new java.lang.invoke API package. invokedynamic facilitates the implementation of dynamic languages ​​(for the JVM) through a dynamic method call. Lambda engineers have chosen a non-dynamic approach to lambdas. Let's see what lambdas are made of:

Program:

 package com.onlyfullstack; public class LambdaInternalWorking { public static void main(String[] args) { Runnable runnable = () -> System.out.println("Calling from Lambda"); } } 

Let's compile the following program:

 javac LambdaInternalWorking.java 

Let's parse the .class file to see its contents:

 javap -p LambdaInternalWorking.class Compiled from "LambdaInternalWorking.java" public class com.onlyfullstack.LambdaInternalWorking { public com.onlyfullstack.LambdaInternalWorking(); public static void main(java.lang.String[]); private static void lambda$main$0(); } 

In this file we cannot see our run () method. Let's check the validity of the class file to get more clarity.

 javap -verbose LambdaInternalWorking.class Classfile onlyfullstack/LambdaInternalWorking.class Last modified 30 Jan, 2019; size 1023 bytes MD5 checksum e99d1d2d0eca865f2f46960aad7216f1 Compiled from "LambdaInternalWorking.java" public class com.onlyfullstack.LambdaInternalWorking minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #7.#17 // java/lang/Object."<init>":()V #2 = InvokeDynamic #0:#22 // #0:run:()Ljava/lang/Runnable; #3 = Fieldref #23.#24 // java/lang/System.out:Ljava/io/PrintStream; #4 = String #25 // Calling from Lambda #5 = Methodref #26.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V #6 = Class #28 // com/onlyfullstack/LambdaInternalWorking #7 = Class #29 // java/lang/Object #8 = Utf8 <init> #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 main #13 = Utf8 ([Ljava/lang/String;)V #14 = Utf8 lambda$main$0 #15 = Utf8 SourceFile #16 = Utf8 LambdaInternalWorking.java #17 = NameAndType #8:#9 // "<init>":()V #18 = Utf8 BootstrapMethods #19 = MethodHandle #6:#30 // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #20 = MethodType #9 // ()V #21 = MethodHandle #6:#31 // invokestatic com/onlyfullstack/LambdaInternalWorking.lambda$main$0:()V #22 = NameAndType #32:#33 // run:()Ljava/lang/Runnable; #23 = Class #34 // java/lang/System #24 = NameAndType #35:#36 // out:Ljava/io/PrintStream; #25 = Utf8 Calling from Lambda #26 = Class #37 // java/io/PrintStream #27 = NameAndType #38:#39 // println:(Ljava/lang/String;)V #28 = Utf8 com/onlyfullstack/LambdaInternalWorking #29 = Utf8 java/lang/Object #30 = Methodref #40.#41 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #31 = Methodref #6.#42 // com/onlyfullstack/LambdaInternalWorking.lambda$main$0:()V #32 = Utf8 run #33 = Utf8 ()Ljava/lang/Runnable; #34 = Utf8 java/lang/System #35 = Utf8 out #36 = Utf8 Ljava/io/PrintStream; #37 = Utf8 java/io/PrintStream #38 = Utf8 println #39 = Utf8 (Ljava/lang/String;)V #40 = Class #43 // java/lang/invoke/LambdaMetafactory #41 = NameAndType #44:#48 // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #42 = NameAndType #14:#9 // lambda$main$0:()V #43 = Utf8 java/lang/invoke/LambdaMetafactory #44 = Utf8 metafactory #45 = Class #50 // java/lang/invoke/MethodHandles$Lookup #46 = Utf8 Lookup #47 = Utf8 InnerClasses #48 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #49 = Class #51 // java/lang/invoke/MethodHandles #50 = Utf8 java/lang/invoke/MethodHandles$Lookup #51 = Utf8 java/lang/invoke/MethodHandles { public com.onlyfullstack.LambdaInternalWorking(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: return LineNumberTable: line 6: 0 line 7: 6 } SourceFile: "LambdaInternalWorking.java" InnerClasses: public static final #46= #45 of #49; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #19 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: #20 ()V #21 invokestatic com/onlyfullstack/LambdaInternalWorking.lambda$main$0:()V #20 ()V 

We don’t need to understand the whole file, we just check the code fragment highlighted in yellow. from lines 73 - 80 contains the code written in the public method static void main (). in line number 78, the JVM makes the called dynamic call for identifier number 2, that is, line number 10. Thus, this call will actually insert the run method and execute it without creating an anonymous class.

For more information, see the links below: https://onlyfullstack.blogspot.com/2019/02/lambda-expression-tutorial-in-java-8.html

https://onlyfullstack.blogspot.com/2019/02/how-lambda-internally-works-in-java-8.html

0
02 Feb '19 at 10:20
source share

The Java compiler will generate synthetic methods for a code construct that is not declared either explicitly or implicitly.

As we know, a lambda expression / function is an implementation of an anonymous class method for an abstract method in the functional interface, and if we see the bytecode of the compiled class file with the lambda expression, instead of creating a new object that wraps the Lambda function, it uses a new instruction INVOKEDYNAMIC to dynamically link this call site to the actual Lambda function, which translates to private static synthetic lambda$0(Ljava/lang/String;)V which will take a string as a parameter .

private static synthetic lambda$0(Ljava/lang/String;)V GETSTAIC java/lang/System.out: Ljava/io/PrintStream; ALOAD 0 INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V RETURN

Example: list.forEach(x-> System.out.println(x));

This lambda expression x-> System.out.println(x) converted to a closed static synthetic block, as mentioned above. But how will this be called for each item in the list when we run the Java class? See the lambda expression link bytecode below for forach accepts a Consumer functional interface object.

INVOKEDYNAMIC accept()Ljava/util/function/Consumer; [ java/lang/invoke/LambdaMetaFactory.metafactory(Ljava/lang/invokeMethodHandler$Lookup.Ljava/lang/invoke/CallSite..//arguments (Ljava/lang/Object;)V//INVOKESTATIC com/<Classname>.lambda$)(Ljava/lang/String;)V, (Ljava/lang/String;)V ]

java.lang.invoke.LambdaMetaFactory : this class provides two forms of communication methods:

  1. Standard version (metafactor (MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)) using the optimized protocol,
  2. Alternative version of altMetafactory (MethodHandles.Lookup, String, MethodType, Object ...)).

These communication methods are designed to support the evaluation of lambda expressions and Java method references. For each lambda expression or method reference, a source type exists in the source code, which is a functional interface. Evaluating a lambda expression creates an object of its target type. The recommended mechanism for evaluating lambda expressions is to disaggregate the lambda body to the method, call the site of the called dynamic call, whose static list of arguments describes the only functional interface method and implementation method desugared, and returns an object (lambda object) that implements the target type. Note (For references to a method, an implementation method is just a reference method; desagering is not required.)

0
Jul 19 '19 at 8:42
source share



All Articles