26 Aprile, 2016 | Di Wellnet

Java 8 e lambda expressions: ne vale davvero la pena?

Java 8 e lambda expressions: ne vale davvero la pena?

È da qualche mese che qui in Wellnet, ci divertiamo con un progetto Java totalmente basato sulla nuova JDK 1.8 e su un framework MVC chiamato Play. A tempo debito dedicheremo un articolo su tutte le skill acquisite durante la realizzazione di questo progetto ma, nel frattempo, ci teniamo a raccontarti e spiegarti un po' delle nuove feature del linguaggio con cui abbiamo avuto modo di giocare in questo periodo. Nel presente articolo parleremo di lambda expressions, un concetto decisamente innovativo per i puristi del Java ma che, a nostro avviso, vale la pena di essere introdotto e magari spiegato con qualche simpatico esempio.

Iniziamo dicendo un'ovvietà: Java è un linguaggio verboso. Spesso, per implementare una funzionalità bisogna scrivere molto più codice rispetto ad altri linguaggi.
 Ipotizziamo ad esempio di voler leggere e stampare a video il contenuto di un file. Ecco due esempi della stessa funzione scritta in Java e in Python.

Lettura file in Java

File dir = new File("."); 
File fin = new File(dir.getCanonicalPath() + File.separator + "Code.txt"); 
FileInputStream fis = new FileInputStream(fin); 
BufferedReader in = new BufferedReader(new InputStreamReader(fis)); 
 
String aLine = null; 
while ((aLine = in.readLine()) != null) { 
    if (aLine.trim().length() == 0) { } 
} 
 
in.close();

Lettura file in Python

myFile = open("/home/xiaoran/Desktop/test.txt") print myFile.read()

Dobbiamo aggiungere altro? Vediamo ora come una lambda può aiutarci a scrivere meno codice e a fare molte altre cose decisamente più utili e interessanti.



Innanzitutto diciamo che una lambda expression deriva direttamente dal mondo del lambda calcolo e altro non è che una rappresentazione concisa di una funzione anonima. Una lambda è innanzitutto una funzione, quindi, a differenza di un metodo, specifica un comportamento senza essere associata per forza a una classe. Una lambda è veloce da scrivere perché ci evita di replicare molto codice inutile, è anonima, quindi non ha bisogno di essere identificata da un nome e, soprattutto, può essere passata come argomento di un metodo che accetta una funzione oppure associata ad una variabile. Ora, se conosci un po' di JavaScript questa cosa non ti stupirà più di tanto ma se sei un javista puro, beh, lasciatelo dire, è un bello shock! Ma come è fatta una lambda? Una lambda expression segue un pattern del genere:

( Parametri della funzione ) -> { corpo della funzione }

Come possiamo vedere un'espressione del genere è formata da tre parti distinte:


  • un insieme di parametri

  • una freccia che separa i parametri dal corpo dell'espressione

  • il corpo dell'espressione che, in questo caso, effettua un confronto tra i nomi di due persone

Proviamo a mostrare qualche esempio pratico di lambda.

(String myString) -> System.out.println(myString); 
()->50;(Person p1) -> p1.talk("I'm John");

La prima espressione prende in input una stringa e la stampa, la seconda espressione non ha parametri e si limita a ritornare un intero di valore 50, la terza invoca il metodo talk dell'oggetto p1, di tipo Person, passato come input.

Ma quando possiamo utilizzare una lambda expression? Una lambda può essere utilizzata per sostituire l'implementazione di un'interfaccia funzionale. Un'interfaccia funzionale è una particolare interfaccia che definisce la signature di un solo metodo. Questa, ad esempio, è un'interfaccia funzionale:

public interface Talker<T>{public void saySomething(T person); 
} 

Quindi una lambda può essere utilizzata ogni volta che è richiesta un’interfaccia funzionale e, soprattutto, permette di implementare il singolo metodo di un’interfaccia funzionale in maniera veloce e poco verbosa.

Facciamo un esempio. Come abbiamo visto, Talker è un’interfaccia funzionale che definisce il metodo saySomething. Possiamo creare un oggetto che implementa Talker in questo modo:

Talker<person> t1 = new Talker<person>() { 
    @Override 
    public void saySomething(Person p) { 
        p.talk("I'm talking");
    } 
}; 

Oppure possiamo fare la stessa identica cosa con una lambda:

Talker<person> t2 = (Person p) -> p.talk("I'm talking too!");

A questo punto, se esistesse un metodo che prende in input un oggetto che implementa Tinker potremmo passargli t1 oppure t2, senza nessuna differenza:

public void letsTalk(Talker t){ 
    t.talk(); 
} 
letsTalk(t1); //I'm talking! 
letsTalk(t2); //'m talking too!

In conclusione abbiamo visto che le lambda expression introducono un concetto nuovo e un nuovo approccio ad alcuni problemi classici di Java. Però ti chiederai: vale davvero la pena introdurre un concetto così particolare solo per scrivere meno codice e renderlo più leggibile?

Nonostante la leggibilità sia negli occhi di chi legge il codice, pensiamo che il gioco valga assolutamente la candela. Scrivere meno codice significa avere programmi più snelli, più manutenibili e, soprattutto, scrivendo meno codice diminuisce il rischio di errori. Un altro aspetto interessante riguarda tutte le nuove funzionalità della JDK che sono legate o si basano sul concetto di lambda, come ad esempio gli operatori aggregati, di cui parleremo in un altro articolo.

Wellnet
Wellnet

Wellnet è una nuova realtà nel panorama delle agenzie digitali italiane: 70 expertise complementari e integrate, con sedi a Milano, Torino Cuneo e Modena, frutto della fusione di tre realtà di successo preesistenti.