Un'espressione lambda è qualcosa di più di una classe interna anonima con un solo metodo?


40

C'è un nuovo clamore con le tanto attese espressioni lambda in Java 8; ogni 3 giorni viene pubblicato un altro articolo con loro su quanto sono belli.

Per quanto ho capito, un'espressione lambda non è altro che una classe interna anonima con un solo metodo (almeno a livello di codice byte). Oltre a questo viene fornito con un'altra bella inferenza tipo-funzione, ma credo che l'equivalente di questo possa essere raggiunto con i generici su un certo livello (ovviamente non in modo così pulito come con le espressioni lambda).

Sapendo questo, le espressioni lambda porteranno qualcosa di più di una zuccherina sintattica in Java? Posso creare classi più potenti e flessibili o altri costrutti orientati agli oggetti con espressioni lambda che non è possibile creare con le funzionalità del linguaggio corrente?


30
Quando una lingua è completa, ogni caratteristica aggiunta potrebbe teoricamente essere descritta come "zucchero sintattico".
Philipp

34
@Philipp: È sbagliato. La caratteristica distintiva dello zucchero sintattico è che la desugarizzazione è puramente locale e non cambia la struttura globale del programma. Ci sono molte funzionalità che non possono essere implementate con solo trasformazioni locali. Ad esempio, se si utilizza un linguaggio ipotetico identico a Java ma con chiamate di coda appropriate, non sarebbe possibile desugar le chiamate di coda a Java "puro" senza trasformare globalmente l'intero programma.
Jörg W Mittag,

2
@Philipp: Purtroppo c'è un solo voto per i commenti, altrimenti voterei il commento di Joerg 1000 volte. No, è sbagliato che qualsiasi caratteristica possa essere descritta come zucchero sintattico. Lo zucchero sintattico non aggiunge nuova semantica. In effetti, AFAIK i lambda Java proposti NON sono zucchero sintattico per speciali classi interne anonime perché hanno una semantica diversa.
Giorgio,

1
@Giorgio: e quali diverse semantiche hanno?
user102008,

2
@Giorgio: Sì, ma la conversione di thisin OuterClass.thisfa parte del processo di de-sugaring delle espressioni lambda in classe anonima.
user102008,

Risposte:


47

tl; dr: mentre è principalmente zucchero sintattico, quella sintassi più piacevole rende molte cose pratiche che finivano in infinite e illeggibili linee di parentesi graffe e parentesi.

Bene, in realtà è il contrario perché le lambda sono molto più vecchie di Java. Le classi interne anonime con un solo metodo sono (erano) il Java più vicino ad Lambdas. È un'approssimazione che è stata "abbastanza buona" per qualche tempo, ma ha una sintassi molto brutta.

In apparenza, i lambda Java 8 sembrano non essere molto più dello zucchero sintattico, ma quando guardi sotto la superficie, vedi tonnellate di astrazioni interessanti. Ad esempio, le specifiche JVM trattano un lambda in modo molto diverso da un oggetto "vero" e mentre è possibile gestirli come se fossero oggetti in cui, non è necessario che JVM li implementi come tali.

Ma mentre tutto quel trucco tecnico è interessante e pertinente (poiché consente future ottimizzazioni nella JVM!), Il vero vantaggio è "solo" la parte sintattica dello zucchero.

Cosa c'è di più facile da leggere:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

o:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

oppure (usando un handle di metodo anziché un lambda):

myCollection.map(String::toUpperCase);

Il fatto che tu possa finalmente esprimere in modo conciso che in precedenza sarebbero 5 righe di codice (di cui 3 sono assolutamente noiose) porta un vero cambiamento di ciò che è pratico (ma non di ciò che è possibile, concesso).


1
Sono totalmente d'accordo con la parte zuccherina della sintassi; la mia domanda era su nuovi costrutti orientati agli oggetti possibili solo con espressioni lambda; dopo tutto Java è un linguaggio orientato agli oggetti. Pensa rispetto ai generici e al modo in cui hanno acquistato molta flessibilità in Java, flessibilità impossibile senza di loro.
m3th0dman,

7
@ m3th0dman: in realtà i generici non hanno aggiunto nuove abilità. A Listpotrebbe contenere qualsiasi oggetto, a List<String>"solo" può contenere stringhe. Generics ha aggiunto una restrizione (e l'opzione per formalizzare le restrizioni!), Non un'aggiunta al potere. Praticamente tutto da quando Java 1.1 è diventato zucchero sintattico. E non è necessariamente una cosa negativa.
Joachim Sauer,

3
@ m3th0dman: In realtà i generici non hanno aggiunto nuove abilità, perché in Java sono solo uno zucchero sintattico. A List<String>è solo un Listcast con da Stringaggiungere attorno ad alcuni valori di ritorno. Tuttavia sono estremamente utili e hanno reso la lingua molto più comoda per scrivere. Le lambda sono casi simili.
Jan Hudec,

3
In realtà è molto più di un semplice zucchero sintattico. Gran parte della funzionalità è implementata come cittadino di prima classe nella JVM attraverso l'uso del bytecode invokedynamic + alcuni progressi piuttosto pesanti nel sistema di inferenza di tipo. Non è implementato come classi interne anonime.
Martijn Verburg,

1
@JanHudec: beh, sono leggermente più dello zucchero sintattico, perché il compilatore li rispetta davvero. Il runtime non si preoccupa di loro, è vero.
Joachim Sauer,

14

Per Java, sì, non è altro che un modo migliore per creare una classe interna anonima. Ciò è dovuto alla decisione fondamentale in Java che ogni bit di codice byte deve vivere all'interno di una classe specifica, che non può essere modificata ora dopo decenni di codice legacy da considerare.

Tuttavia, questo non è esattamente ciò di cui parlano le espressioni lambda. Nei formalismi in cui sono concetti nativi piuttosto che una contorsione da salto sul carro, gli lambda sono elementi costitutivi fondamentali; sia la sintassi che l'atteggiamento delle persone nei loro confronti sono molto diversi. L'esempio di una funzione ricorsiva anonima creata esclusivamente da lambda in Struttura e interpretazione dei programmi per computer è in grado di cambiare l'intera concezione del calcolo. (Tuttavia, sono abbastanza certo che il modo di imparare a programmare è solo per esoterico diventare una storia di successo mainstream.)


1
Imparare che tutto può essere implementato in termini di lambda è molto istruttivo e non "esoterico" secondo me. (Tuttavia, immagino che la maggior parte dei "programmatori" non si preoccupino dell'interessante teoria CS.) Ciò non significa che lambdas sia speciale; significa solo che i lambda sono un tipo di costrutto universale. Ce ne sono altri, come i combinatori SKI. Le lambda sono elementi fondamentali nei paradigmi funzionali, ma forse qualcos'altro può essere fondamentale in un altro paradigma.
user102008

+1 per "la contorsione del carrozzone": spesso mi chiedo perché alcune lingue continuino a cambiare per imitare altre lingue popolari e perché i programmatori ce la facciano. Mi piacciono i lambda e li uso molto in Scala, Lisp, Haskell, ma in Java o C ++ si sentono come un ripensamento legato al linguaggio solo perché sono diventati popolari in altre lingue.
Giorgio,

2

Sì, è solo uno zucchero sintattico, nel senso che ovunque tu scriva un lambda, puoi riscrivere quell'espressione come un'espressione di classe interna anonima con un metodo, dove la classe implementa l'interfaccia funzionale dedotta per il contesto del lambda, e sarebbe esattamente equivalente semanticamente. E puoi farlo semplicemente sostituendo l'espressione lambda con l'espressione di classe anonima, senza cambiare altre espressioni o righe di codice.


1
perché downvote? quello che ho detto è completamente corretto
user102008

Quello che scrivi suona una proposta ragionevole per lambda Java ma questa proposta è stata scartata a favore di un'altra ( doanduyhai.wordpress.com/2012/07/12/… ).
Giorgio,

1
@Giorgio: non sto "proponendo" nulla. Cosa, esattamente, non sei d'accordo con quello che ho detto? Sì, l'interno dell'espressione avrà un aspetto diverso, ad es. Aggiungeremo un metodo e sì, thisdovrà essere convertito in OuterClass.this. Ciò non contraddice ciò che ho detto: ogni espressione lambda può essere convertita in un'espressione di classe anonima semanticamente equivalente senza alterare nulla al di fuori di tale espressione . Non ho detto che l'interno non sarebbe cambiato.
user102008,

3
Quello che hai detto non è corretto. La semantica delle classi interne lambda e anon non è esattamente la stessa (sebbene siano simili). In cima alla mia testa, il significato del significato di questo cambia; e altre classi interne risultano sempre in una nuova istanza di un oggetto, mentre una lambda potrebbe o meno.
Stuart segna il

1
@StuartMarks: No, non hai letto la mia risposta. Non ho detto che ognuno di loro può fare tutto ciò che l'altro fa. Ho detto che un lambda ha una classe anonima equivalente che è semanticamente la stessa. Come ho già detto nei commenti, thisin lambda fa parte dello zucchero sintattico e non fa differenza nella semantica. E sulle differenze di implementazione, implementazione! = Semantica. Informazioni sulle differenze nell'identità dell'oggetto; l'identità dell'oggetto è estremamente tangente alla funzionalità di lambda; nessuno controlla l'identità dell'oggetto delle classi lambdas / anon comunque perché non è utile.
user102008,

1

Joachim Sauer ha già fatto un buon lavoro nel rispondere alla tua domanda, ma ha solo accennato a qualcosa che considero importante. Poiché i Lambdas non sono classi, non vengono nemmeno compilati come tali. Tutte le classi interne anonime comportano la creazione di un file .class che a sua volta deve essere caricato da ClassLoader. Quindi l'utilizzo di Lambdas non solo rende il codice più bello, ma riduce anche le dimensioni del codice compilato, l'impronta di memoria del ClassLoader e il tempo necessario per trasferire i bit dal disco rigido.


-1

No non lo sono.

Un altro modo per dirlo è che i lambda sono un modo non orientato agli oggetti, per quanto conciso, per ottenere la stessa cosa che una classe anonima o, la mia preferenza, una classe interiore raggiungerebbe in modo orientato agli oggetti.


1
La programmazione funzionale può essere totalmente ortogonale alla programmazione orientata agli oggetti (vedere: Scala e F #). Questo sembra l'opinione di qualcuno a cui semplicemente non piace la programmazione funzionale per principio.
KChaloux,

1
@KChaloux - Non un odiatore di programmazione funzionale. La risposta è scritta da qualcuno che preferisce avere un martello E un cacciavite piuttosto che un martello. La programmazione OO è un buon paradigma, così come la programmazione funzionale. La mia preferenza in una lingua è che sia chiara sulle sue intenzioni. Lambdas Mi sento fangoso la natura altrimenti OO di Java. Java non è stato progettato per essere un linguaggio funzionale. Gli esseri umani hanno bisogno di una struttura per fare il loro miglior lavoro.
Guido Anselmi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.