2013-02-09 10 views
8

Capisco la chiusura e ho applicato in alcune lingue come Python e SML. Tuttavia, quando leggo wikipedia sulla chiusura in Java (ovviamente, solo la versione 8), non capisco la differenza se Java supporta la chiusura o no nel loro esempio.Java: spiega Chiusura in questo codice

Coloro codice copio da Wikipedia: Closure

il codice Java senza chiusura:

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

E se Java supporta la chiusura, il codice appare come:

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

Quindi, la mia domanda è: se Java supporta la chiusura, quale particolarità nel secondo codice? Davvero non vedo la differenza principale tra due codici.

Per favore dimmi questo punto.

grazie :)

risposta

2

La differenza è che:

  • nel primo caso si dichiara una classe anonima e la creazione di un'istanza, ma
  • nel secondo caso non esiste una categoria e nessuna istanza Invece, c'è una lambda ... efficacemente una funzione anonima.

Essi raggiungere uno stesso risultato, ma la sintassi lambda è certamente più leggero.

Tuttavia, un lambda può accedere solo alle variabili locali nell'ambito in cui è dichiarato se sono final (o effettivamente finale); vedi 15.27.2 nella bozza # 2 della recensione JSR-000335. Quindi potresti obiettare che i lambda Java non sono completamente chiusi.

Ma la specifica JSR-000335 implica che i lambda NON sono classi anonime. E this e super in un corpo lambda hanno un significato diverso che fanno in un metodo.

La specifica descrive lambdas (in un punto) come implementato utilizzando "classi sintetiche" e afferma che un'istanza delle classi sintetiche può essere riutilizzata, se del caso, come ottimizzazione della compilazione. (Al contrario, il compilatore non sarebbe autorizzato a fare quell'ottimizzazione per una classe anonima.) Questa ottimizzazione significa che i lambda sono probabili con prestazioni migliori rispetto all'equivalente codificato usando classi anonime.

+1

È ancora un'istanza di una classe anonima. E no, non è più potente. – newacct

4

Il punto è che in realtà non sono così diversi funzionalmente:

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

equivale ad una nuova classe di un'istanza Runnable con un'implementazione equivalente del metodo run(). Sostituisci molto codice "piastra caldaia" con una semplice funzione lambda.

Utilizzando il lambda, il codice diventa molto più espressivo, conciso, più facile da scrivere e molto leggibile. Ed è proprio qui che iniziano i benefici, una volta entrati nel mondo delle chiusure e delle funzioni lambda.

0

Bene, ci sono principalmente due differenze. Il primo è collegato al processo sottostante in corso in Javac e JVM e il secondo è la sintassi.

Prima di dare una spiegazione, consente di definire molto rapidamente cos'è una chiusura nel linguaggio funzionale "reale": una funzione che si accompagna al suo ambiente lessicale e al contesto di memoria.

Inizialmente, il compilatore risolverà questo codice "scandendo" il "contesto syntaxiq" in cui verrà eseguito il codice (non le variabili, ma il codice che scrivi causa il controllo statico del compilatore). Se rileva che stai scrivendo una lambda come parametro di un metodo che è in attesa di un'interfaccia funzionale, sarai in grado di compilare in modo che la JVM sia in grado di trovare la giusta pace di codice da eseguire. Di fatto implementerai un'interfaccia che espone solo una firma al volo.

Poi, la sintassi di per sé è importante perche 'non vi darà lo stesso potere di una classe anonima, dove sarà in grado di implementare o sostituire diversi metodi nello stesso luogo.

Il pezzo di codice nella domanda non è molto pertinente per vedere la differenza tra i due concetti e non sta usando "chiusura" nel suo intero. Ecco un pezzo di codice che potrebbe aiutare te vedere il potenziale:

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

Questa compilazione in Java 8 e stamperà: 20

Ma, c'è qualcosa di strano in Java con chiusura. Questo pezzo di codice viene dalla online documentation, 14:

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

questo stampa Howdy, world!

E questo è proprio quello che non si vuole in un linguaggio di programmazione funzionale. La JVM fa questo perché Java è un linguaggio orientato agli oggetti ed è piuttosto bravo a farlo.

In Java si utilizzano molti riferimenti all'heap (che sono vicini ai puntatori in una lingua come C o C++ ancora più vicino). Con questo principio, è possibile modificare una variabile avviata nel contesto della memoria del programma se si è incorporato un riferimento ad esso nella pila di esecuzione. Questo è il principio implicito proveniente dallo Von Neumann Architecture. Questo differisce da un linguaggio funzionale che dovrebbe racchiudere tra loro contesti di esecuzione diversi, che è sottilmente diverso e ti garantirà che un valore riferito da una variabile non verrà modificato da un successivo assegnamento della variabile. Ma questa è un'altra storia.

Problemi correlati