Loop.times(5, () -> { System.out.println("looping"); });
它可以有效地编译到哪一个?
for(int i = 0; i < 5; i++) System.out.println("looping");
或类似的东西
new CallableInterfaceImpl(){ public void call(){ for(int i = 0; i < 5; i++) System.out.println("looping"); } }.call();
那么它会替代(某种内联),还是实际上创建一个匿名类?
VM决定如何实现lambda,而不是编译器。
请参阅《 Lambda表达式的翻译》中的Translation strategy部分。
Translation strategy
我们没有生成字节码来创建实现lambda表达式的对象(例如,调用内部类的构造函数),而是描述了构造lambda的方法,并将实际构造委托给语言运行时。该配方被编码在invokedynamic指令的静态和动态参数列表中。
for 就简单的编译或性能而言,从你的示例中进行构造是最有效的方法(但根据测试,性能差异很小)。
for
插件:
我创建并分解了两个示例:
for (String string: Arrays.asList("hello")) { System.out.println(string); }
反汇编的字节码,常量和其他信息:
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 }
和
Arrays.asList("hello").forEach(p -> {System.out.println(p);});
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 }
对于Lambda示例,编译器生成的类文件更复杂且更大(771b对1262b)。