2015-02-01 16 views
5

Recentemente ho sono imbattuto in un presentation da EclipseCon 2014, dove a pagina 5 dicono "espressioni Lambda permettono di trattare il codice come dati".Che cosa significa "Codice come dati"?

Ho anche imbattuto in questo esempio di codice

button.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent event) { 
     System.out.println("button clicked"); 
    } 
}); 

da "Java 8 Lambda: pragmatico programmazione funzionale" di Richard Warburton dove dice

"Questo è in realtà un esempio di utilizzo di codice come dati: stiamo dando al pulsante un oggetto che rappresenta un'azione. "

Cosa codice come dati significa rispetto alle espressioni lambda e/o classe interna anonima?

+0

Immagino che si riferisca al passaggio di un metodo come valore, che lambda da l'illusione di fare. I valori sono visti come dati e "codice" si riferisce probabilmente al blocco di codice che è il metodo –

+0

Sembra un linguaggio funzionale che tratta le funzioni come _prime class citizens_ (il concetto di dare una funzione come input per un'altra funzione). Questo esempio mi sembra abbastanza disordinato, altri linguaggi funzionali o ibridi-funzionali fanno un lavoro migliore con la sintassi, per esempio controlla Scala (che è ancora basato sulla JVM). – Marcs

+0

"Il codice come dati" è uno slogan che non significa nulla che non sapessi già. – immibis

risposta

1

L'idea di "codice come dati" è strettamente correlata al concetto di linguaggi di programmazione con funzioni di prima classe. Vedere lo Wikipedia article su questo argomento. In questo other answer parlo se Java ha funzioni di prima classe, ma quell'articolo discute anche di altri problemi.

La definizione alle voci di Wikipedia (che cita Abelson & Sussman, Struttura e Interpretazione dei programmi per computer, sezione 1.3) menziona specificamente le seguenti caratteristiche delle funzioni che li rendono "di prima classe":

  • possono essere passati come argomenti per altre funzioni
  • possono essere restituiti come valori da altre funzioni
  • possono essere assegnati alle variabili
  • può essere memorizzato in strutture dati

Queste sono tutte le cose che si fanno con i dati. Se riesci a fare queste stesse cose con le funzioni, allora è come trattare "codice come dati".

Se si osserva da vicino come lambdas è stato aggiunto al linguaggio di programmazione Java, si vedrà che un lambda viene realmente convertito in un'istanza di un'interfaccia funzionale. In quanto tale, è un'istanza di qualche oggetto, e quindi un discendente della classe Object, e come tutti gli oggetti in Java, ha i metodi equals(), hashCode(), getClass() ecc. E i riferimenti possono essere confrontati con == e così via. Tuttavia, sei esplicitamente scoraggiato dal basarti su tutto ciò. Vedere il mio other answer per ulteriori discussioni. In pratica, quando si utilizza lambdas in Java, sembra davvero di passare il codice come argomento o assegnarlo a una variabile. Ad esempio,

list.replaceAll(x -> doSomething(x)); 

Predicate<String> pred = s -> s.length() > 5; 

È davvero finisce per non pensare al fatto che, sotto le coperte, lambda sono oggetti che sono istanze di interfacce funzionali.

5

Come si passa la funzionalità come argomento a un altro metodo, ad esempio quale azione deve essere eseguita quando qualcuno fa clic su un pulsante come il codice di esempio.

Le espressioni lambda consentono di eseguire questa operazione, per trattare la funzionalità come argomento metodo = code as data.

Vedere oracle link per ulteriori informazioni e esempi di codice lambda.

1

significa che il codice del programma si scrive è anche un dati che può essere passato come argomento ad un altro method e manipolati da un programma.

1

Nell'età d'oro di Java, non esisteva un paradigma conveniente per il passaggio di funzionalità da un chiamante a un destinatario. Dovevi hackerare insieme una classe con qualche metodo (di solito tramite lo schema di progettazione "Command") e poi passarlo al destinatario.

Java 8 Lambdas ha spostato il paradigma introducendo espressioni Lambda. Dimenticandosi di come questi sono rappresentati al runtime, Lambdas appare allo sviluppatore come puro codice che può essere passato ai metodi. Codice come dati!

Questo cambio di paradigma ha aperto la strada a java.util.Stream che accetta espressioni lambda che indicano a una raccolta di eseguire una funzionalità.

Un trattamento splendidamente chiaro, conciso e completo dell'intero argomento è il nuovo libro di Maurice Naftalin, Mastering Lambdas - Java Programming in a Multi-Core World.

1

Il codice è sempre dati! Le istruzioni bytecode per un programma sono memorizzate. Il programmatore non ha accesso diretto in lettura e scrittura a questa memoria, ma è lì.

Quando parliamo di "trattare" il codice come dati, ci riferiamo alla memorizzazione di riferimenti a quella memoria in un modo che possa essere utilizzato e organizzato nel modo in cui solitamente pensiamo ai "dati".

Per esempio, si potrebbe immaginare che dentro button sembra qualcosa di simile:

class Button { 
    private ActionListener[] listeners = new ActionListener[100]; 
    private int count = 0; 

    public void addActionListener(ActionListener listener) { 
     listeners[count] = listener; 
     ++count; 
    } 

    // called somehow when the button is clicked 
    void notifyListeners() { 
     ActionEvent theEvent = new ActionEvent(...); 
     for(int i = 0; i < count; ++i) { 
      listeners[i].actionPerformed(theEvent); 
     } 
    } 
} 

Essenzialmente Button è mantenere un elenco di funzioni in un array: questo è trattare il codice come dati. Nella maggior parte dei casi uno ActionListener non ha altro scopo se non quello di fare riferimento a un particolare override di actionPerformed.

Poiché tutti i metodi di istanza Java sono virtuali, possiamo sempre considerare il codice come dati. Ciò è dimostrato dall'elaborato framework di ascolto degli eventi di AWT/Swing. Le espressioni lambda aggiungono solo enfasi concettuale e breve sintassi. (Anche un aumento di prestazioni nella maggior parte delle situazioni a causa della loro implementazione.)

Lambdas ci consente di esprimere più chiaramente il nostro intento quando utilizziamo un oggetto solo per implementare un metodo particolare, non per memorizzare valori.

Tecnicamente parlando, tutto avviene tramite indirezione. Un ActionListener non contiene il codice: invece, la macchina virtuale sa in qualche modo (che non siamo a conoscenza) che punta a una particolare struttura in memoria che contiene un puntatore al codice. Quindi una sorta di riferimento al codice è ciò che viene effettivamente passato in giro, quindi "tratta il codice come dati".