2016-06-22 7 views
8

Ich bin ein wenig verwirrt über Java Lambdas und Methodenreferenzen Verhalten. . Für die Ex, haben wir diesen Code:Warum verhalten sich der äquivalente Lambda-Ausdruck und die Methodenreferenz beim Erfassen des statischen Feldwerts anders?

import java.util.function.Consumer; 

public class Main { 

    private static StringBuilder sBuilder = new StringBuilder("1"); 

    public static void main(String[] args) { 
     Consumer<String> consumer = s -> sBuilder.append(s); 
     sBuilder = new StringBuilder("2"); 
     consumer.accept("3"); 
     System.out.println(sBuilder); 
    } 

} 

Ausgang:

23 

Dies funktioniert wie erwartet, aber wenn wir

s ersetzen -> sBuilder.append (e)

mit

sB uilder :: anhängen

wird der Ausgang sein:

2 

Sie irgendwelche Ideen, wie dies zu erklären? Das sind nicht die gleichen Dinge? Vielen Dank.

+1

Ist [diese] (http://stackoverflow.com/questions/30514995/what-is-the-difference-between-a-lambda-and-a-method-reference-at-a -runtime-leve) zu kompliziert für ein Duplikat? –

+0

@SotiriosDelimanolis ein bisschen :) danke für nützliche Hinweise und Antwort – j2esu

Antwort

10

Im Lambda-Ausdruck wird das Feld sBuilder erfasst, aber nicht ausgewertet. Es wird nur ausgewertet, wenn die entsprechende Funktionsschnittstellenmethode aufgerufen wird. An diesem Punkt verweist auf die sBuilder die neue Instanz erzeugt und das Feld zuzugeordnet mit

sBuilder = new StringBuilder("2"); 

Bei dem Verfahren Referenz des sBuilder Feld unmittelbar ausgewertet wird eine Consumer Instanz zu erzeugen. Dieser Wert verweist auf das Beispiel in dem statischen Initialisierer erstellt

private static StringBuilder sBuilder = new StringBuilder("1"); 

und die Consumer wird auf, dass man arbeiten. Sie drucken das neue.


Aus der Java Language Specification, die Methode Run-Time Evaluation of Method References

Der Körper eines Aufrufs betreffend hängt von der Form des Ausdrucks Methode Referenz, wie folgt:

Wenn das Formular ExpressionName :: [TypeArguments] Identifier oder Primary :: [TypeArguments] Identifier, dann hat der Rumpf der Aufrufmethode den Effekt eines Methodenaufrufausdrucks für a comp iile-time-Deklaration, die die Kompilierzeit-Deklaration des Methodenreferenzausdrucks ist. Laufzeitauswertung des Verfahrens Aufrufausdruck wird wie in §15.12.4.3 angegeben, §15.12.4.4 und §15.12.4.5, wobei gilt:

  • Der Aufrufmodus von der Übersetzungszeit abgeleitet wird, Erklärung gemäß § 15.12.3. bestimmt

  • Der Zielbezug ist der Wert von ExpressionName oder Primary, wenn die Expressionsverfahren Referenz wurden bewertet.

  • Die Argumente für den Methodenaufrufausdruck sind die formalen Parameter der Aufrufmethode.

+1

Mit anderen Worten, 's -> sBuilder.append (s)' ist äquivalent zu 's -> Main.sBuilder.append (s)', während ' sBuilder :: append' ist äquivalent zu 'StringBuilder temp = Main.sBuilder; s -> temp.append (s) ' –

+1

@TavianBarnes Sie können das bearbeiten, wenn Sie möchten. –

+0

Aus Neugier, warum markieren Sie es zunächst als Community-Wiki? –

Verwandte Themen