2013-02-09 6 views
8

Ich verstehe Schließung und in einigen Sprachen wie Python und SML angewendet haben. Dennoch, wenn ich Wikipedia über Schließung in Java (natürlich nur Version 8) lese, verstehe ich keinen Unterschied, ob Java in ihrem Beispiel die Schließung unterstützt oder nicht.Java: erklären Closure in diesem Code

Diejenigen Code, den ich aus Wikipedia kopieren: Closure

Der Java-Code ohne Verschluss:

class CalculationWindow extends JFrame { 
    private volatile int result; 
    ... 
    public void calculateInSeparateThread(final URI uri) { 
    // The expression "new Runnable() { ... }" is an anonymous class implementing the 'Runnable' interface. 
    new Thread(
     new Runnable() { 
     void run() { 
      // It can read final local variables: 
      calculate(uri); 
      // It can access private fields of the enclosing class: 
      result = result + 10; 
     } 
     } 
    ).start(); 
    } 
} 

Und wenn Java-Verschluss unterstützt, sieht der Code wie:

class CalculationWindow extends JFrame { 
private volatile int result; 
    ... 
    public void calculateInSeparateThread(final URI uri) { 
    // the code() -> { /* code */ } is a closure 
    new Thread(() -> { 
     calculate(uri); 
     result = result + 10; 
    }).start(); 
    } 
} 

So, Meine Frage ist: Wenn Java den Abschluss unterstützt, welches spezielle Ding im zweiten Code? Ich sehe wirklich keinen Hauptunterschied zwischen zwei Codes.

Bitte sagen Sie mir diesen Punkt.

Dank :)

Antwort

2

Der Unterschied ist, dass:

  • im ersten Fall eine anonyme Klasse deklarieren und eine Instanz zu schaffen, aber
  • im zweiten Fall gibt es keine Klasse und keine Instanz. Stattdessen gibt es ein Lambda ... effektiv eine anonyme Funktion.

Sie erreichen das gleiche Ziel, aber die Lambda-Syntax ist sicherlich mehr leicht.

Ein Lambda kann jedoch nur auf lokale Variablen in dem Bereich zugreifen, in dem er deklariert ist, wenn sie final (oder effektiv endgültig) sind; siehe 15.27.2 in JSR-000335, Übersichtsvorlage Nr. 2. Man könnte also argumentieren, dass Java-Lambdas keine vollständigen Schließungen sind.

Die JSR-000335-Spezifikation besagt jedoch, dass Lambdas keine anonymen Klassen sind. Und this und super in einem Lambda-Körper haben eine andere Bedeutung, die sie in einer Methode tun.

Die Spezifikation beschreibt lambdas (an einem Punkt) als implementiert mit "synthetischen Klassen" und besagt, dass eine Instanz der synthetischen Klassen gegebenenfalls als Kompilierungsoptimierung wiederverwendet werden kann. (Im Gegensatz dazu wäre es dem Compiler nicht möglich, diese Optimierung für eine anonyme Klasse vorzunehmen.) Diese Optimierung bedeutet, dass lambdas wahrscheinlich besser abschneiden als das Äquivalent, das mit anonymen Klassen codiert wurde.

+1

Es ist immer noch eine Instanz einer anonymen Klasse. Und nein, es ist nicht mächtiger. – newacct

4

Der Punkt ist, dass sie so unterschiedlich sind funktionell nicht wirklich:

() -> { 
    calculate(uri); 
    result = result + 10; 
} 

zu einer neuen Klasse Instanz Runnable mit einer äquivalenten Umsetzung der Lauf entspricht() Methode. Sie ersetzen eine Menge "Boiler-Platte" Code mit einer einfachen Lambda Funktion.

Mit dem Lambda wird Ihr Code viel expressiver, prägnanter, einfacher zu schreiben und sehr lesbar. Und genau hier beginnen die Vorteile, sobald Sie die Welt der Schließungen und Lambda-Funktionen betreten.

0

Nun, es gibt hauptsächlich zwei Unterschiede. Der erste ist mit dem zugrunde liegenden Prozess verbunden, der in Javac und der JVM passiert, und der zweite ist die Syntax.

Bevor wir eine Erklärung geben, wollen wir sehr schnell definieren, was eine Schließung in einer "echten" funktionalen Sprache ist: eine Funktion, die mit ihrer lexikalischen Umgebung und ihrem Speicherkontext einhergeht.

Zuerst wird der Compiler diesen Code auflösen, indem er den Syntaxiq-Kontext "scannt", in dem der Code ausgeführt wird (nicht die Variablen, aber der Code, den Sie schreiben, verursacht statische Tests). Wenn Sie feststellen, dass Sie ein Lambda als Parameter einer Methode schreiben, die auf eine funktionale Schnittstelle wartet, können Sie kompilieren, sodass die JVM den richtigen Codecode zur Ausführung finden kann. In der Tat werden Sie eine Schnittstelle implementieren, die nur eine Signatur im laufenden Betrieb verfügbar macht.

Dann ist die Syntax an sich wichtig, weil sie Ihnen nicht die gleiche Power wie eine anonyme Klasse bietet, in der Sie mehrere Methoden an derselben Stelle implementieren oder überschreiben können.

Das Stück Code in der Frage ist nicht sehr relevant, um den Unterschied zwischen den beiden Konzepten zu sehen, und es verwendet nicht "Schließung" in seiner Gesamtheit. Hier ist ein Stück Code, das helfen te das Potenzial sehen konnte:

public class MyClass 
{ 
    // A one method interface. 
    public static interface Function 
    { 
     void execute(int a); 
    }; 

    // An implementation of Function using the closure and lambda. 
    public static Function createPrintAddToTenFunction() 
    { 
     Integer x = 10; 
     Function func = (a) -> System.out.println(x + a); 
     return func; 
    } 

    // A basic program. 
    public static void main(String args[]) 
    { 
     Function func = createPrintAddToTenFunction(); 
     func.execute(10); 
    } 
} 

Diese kompilieren in Java 8 und drucken: 20

Aber es ist etwas seltsam in Java mit Verschluss. Dieses Stück Code kommt aus dem online documentation, 14 Eintrag:

public static void main(String... args) { 
    StringBuilder message = new StringBuilder(); 
    Runnable r =() -> System.out.println(message); 
    message.append("Howdy, "); 
    message.append("world!"); 
    r.run(); 
} 

wird Howdy, world!

Dieser Druck Und das ist genau das, was Sie wollen nicht in einer funktionalen Programmiersprache. Die JVM tut dies, weil Java eine objektorientierte Sprache ist und ziemlich gut darin ist.

In Java verwenden Sie viele Referenzen auf den Heap (die nahe an Zeigern in einer Sprache wie C oder dem noch näher C++ sind). Mit diesem Prinzip können Sie eine im Speicherkontext des Programms initiierte Variable ändern, wenn Sie im Ausführungsstapel einen Verweis darauf eingebettet haben. Das ist das implizite Prinzip, das von der Von Neumann Architecture kommt. Dies unterscheidet sich von einer funktionalen Sprache, die verschiedene Ausführungskontexte ineinander einschließen sollte, die sich subtil unterscheiden und sicherstellen, dass ein von einer Variablen referenzierter Wert nicht durch eine spätere Zuweisung der Variablen modifiziert wird. Aber das ist eine andere Geschichte.

Verwandte Themen