2013-05-30 10 views
45
Loop.times(5,() -> { 
    System.out.println("looping"); 
}); 

Quale di questi sarebbe effettivamente compilare?Come verranno compilate le funzioni lambda Java?

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

o qualcosa di simile

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

Quindi sarebbe sostituire (tipo di linea), o addirittura creare una classe anonima?

+4

Non sono sicuro dei dettagli, ma l'idea generale è che javac converta un'espressione lambda in un'istruzione piuttosto astratta, che non determina come viene creata in fase di esecuzione. È la JVM che decide cosa fare. Nel peggiore dei casi, un'espressione lambda = 'new' una classe anonima. Nel migliore dei casi, un'espressione lambda = un oggetto memorizzato globalmente. Nell'esempio, l'espressione lambda potrebbe essere equivalente a un oggetto Runnable finale statico, creato una volta e memorizzato nella cache nella classe. – ZhongYu

+1

Vedere anche [java-8-lambda-expression-and-first-values-values] (http://stackoverflow.com/questions/15221659/java-8-lambda-expression-and-first-class-values) – nawfal

risposta

35

La VM decide come implementare lambda, non un compilatore.

Vedere la sezione Translation strategy in Translation of Lambda Expressions.

Invece di generare bytecode per creare l'oggetto che implementa l'espressione lambda (ad esempio chiamando un costruttore per una classe interna), si descrive una ricetta per costruire il lambda, e delegare la costruzione effettiva al runtime linguaggio. Quella ricetta è codificata negli elenchi di argomenti statici e dinamici di un'istruzione invokeynamic.

for costruzione dal vostro esempio è il modo più efficace in termini di semplice compilazione o di perfomance (ma le differenze di prestazioni sono molto piccole, con le prove).

Addon:

ho creato e smontare due esempi:

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

smontati bytecode, costanti e altre informazioni:

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 

} 

e

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

bytecode smontato, costanti e altre informazioni:

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 
} 

compilatore genera file di classe è più complicato e più grandi (771b vs 1262b) per Lambda esempio.

+11

E 'Arrays.asList (" ciao "). ForEach (System.out :: println);'? – JAB

+0

il compilatore può ancora compilare il lambda con un output bytecode compatibile con Java 7 o inferiore tramite http://stackoverflow.com/a/43572220/995714 –

+0

Quale strumento stai usando qui per mostrare il codice byte disassemblato? Sembra abbastanza elegante. – barneypitt

Problemi correlati