2014-02-18 4 views
19

Betrachten Sie das folgende Java 8-Snippet.Worum besteht ein kompilierter Java 8 Lambda-Ausdruck?

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); 
} 

Was wird Consumer<Integer> consumer = x -> System.out.print(x) kompiliert?

Ich verstehe, dass Lambdas nicht als anonyme innere Klassen implementiert sind. Jedoch Consumer<Integer> ist eine Schnittstelle daher x -> System.out.print(x) muss ein Objekt von irgendeiner Art produzieren, aber es ist nicht klar, welche Art von Objekt produziert wird.

Gibt es einen neuen Objekttyp in Java 8, der einen Lambda-Ausdruck darstellt?

Update Hier ist das dekompilierte Programm das Programm wurde mit der Eclipse Java 8 Compiler erfüllt und die Ausgabe unten ist von Eclipse, wenn Sie eine Klassendatei öffnen.

Es sieht so aus, dass der Lambda-Ausdruck auf der Klasse in eine statische Methode verwandelt, der den Lambda-Ausdruck 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} 
} 
+1

Try 'consumer.getClass()' für Hinweise, dann lesen [diese] (http://docs.oracle.com/javase/tutorial/ java/javaOO/lambdausexpressions.html) und dann die JLS. –

+1

@SotiriosDelimanolis 'consumer.getClass()' outputs Beispiel $$ Lambda $ 1/1072591677 – ams

+0

Verwenden Sie 'javap -c YourClass.class', um zu überprüfen, wie der Code kompiliert wird. –

Antwort

7

Die current draft of the Java 8 Language Specification Staaten (Kapitel 15.27.4)

Das enthält Wert eines Lambda-Ausdrucks ist ein Verweis auf eine Instanz einer Klasse mit den folgenden Eigenschaften:

  • Die Klasse implementiert die Zielfunktionsschnittstelle und, falls der Zieltyp ein Schnitttyp ist, jedes andere Schnittstellenelement der Schnittmenge.
  • Die Klasse deklariert eine Methode, die die abstrakten Methoden der Funktionsschnittstelle Supertype (und möglicherweise einige andere Methoden ihrer Superschnittstellen) außer Kraft setzt.
  • Die Parametertypen, Rückgabetypen und geworfenen Typen der Methode werden vom Funktionstyp der Schnittstelle angegeben.
  • Der Körper der Methode hat die Wirkung, den Lambda-Körper zu bewerten, wenn es ein Ausdruck ist, oder den Lambda-Körper auszuführen, wenn es ein Block ist; Wenn ein Ergebnis erwartet wird, wird es von der Methode zurückgegeben.
  • Die Klasse überschreibt keine anderen Methoden der oben genannten Schnittstelle oder Schnittstellen, außer dass sie Methoden der Klasse Object überschreiben kann.

Beachten Sie, dass die JLS sagt nichts darüber, wie der Code sollte außer kompiliert werden, dass der Byte-Code die Spezifikation oben unterstützen sollte.

Als solche wird die Aufgabe durch das Lambda-Ausdruck zurückgegeben

x -> System.out.print(x); 

wird eine Instanz einer Klasse sein, die die oben genannten Regeln folgt.

Ihren Kommentar Da

consumer.getClass() 

gibt die folgende Klasse

Example$$Lambda$1/1072591677 

es scheint, dass es eine Proxy-Klasse wie spezifisch für Lambda-Ausdrücke erzeugt.

Siehe hier:

+0

Beachten Sie, dass Lambdas in der Java 8-Release-Implementierung nicht in separate Klassendateien kompiliert werden. –

+0

@victor Recht, das sind alle Laufzeit Klassen generiert. –

+0

Jetzt sind sie nicht einmal Klassen. Wenn Sie getClass() aufrufen, erhalten Sie nur eine Ausnahme. – Trejkaz