Java 8: Espressioni Lambda in 5 minuti

Java 8 Lambda: cosa sono

Le espressioni Lambda costituiscono la principale novità per il linguaggio di programmazione Java 8. Esse sono collegate al concetto di funzione anonima (funzione non classe anonima), ossia una funzione che ha un corpo ma non un nome, definita nel punto in cui viene utilizzata. La loro sintassi è qualcosa di simile:

(arg1, arg2) -> {body}

Java 8 Lambda: Esempi
// espressione che prende in input due interi e restituisce la somma
(int x, int y) -> x + y

// espressione che prende in input una stringa e restituisce la sua lunghezza
s -> s.length()

// espressione senza argomenti che restituisce il valore 50
() -> 50

// espressione che prende in input una stringa e non restituisce nulla
(String s) -> { System.out.println(“Benvenuto “);
System.out.println(s); }

//ERRORE
(int x, 5) -> x + y
In un’espressione lambda o nessuno dei tipi dei parametri è dichiarato oppure lo devono essere tutti. Se c’è solamente un parametro, le parentesi tonde possono essere omesse,
Vengono chiamate interfacce funzionali (functional interface) delle interfacce con un solo metodo astratto. Sono generalmente marcate con l’annotazione @FunctionalInterface, anche se non è obbligatorio. Le lambda sono usate con le funcional interface.

Esempio:
// Anonymous Runnable
Runnable r1 = new Runnable(){

@Override
public void run(){
System.out.println(“Hello world old style!”);
}
};

// Lambda Runnable
Runnable r2 = () -> System.out.println(“Hello world with Lambda!”);

E’ abbastanza evidente come con l’uso delle lambda abbiamo ridotto un pezzo di codice da 5 linee a 1 soltanto.
Esempio:

//Prima:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(“Sintassi arcinota!”);
}
});

//Dopo:
button.addActionListener( (e) -> {
System.out.println(“Nuova sintassi!”);
});

Ricapitolando, l’espressione lambda è una sintassi più semplice e leggibile per definire-creare un’istanza di una classe anonima che implementa un’interfaccia con un solo metodo astratto. Esse si concentrano solamente sulla definizione dell’unico metodo astratto dell’interfaccia.

Usando le espressioni lambda si può utilizzare un altro strumento aggiunto con java8, i reference method. E’ una nuova sintassi per poter invocare un metodo o un costruttore già esistente.
Esempio:
class Numbers {
public static boolean isMoreThanFifty(int n1, int n2) {
return (n1 + n2) > 50;
}

}

public static void main(String[] args) {

// Using an anonymous class
BiPredicate<Integer, Integer> a = new BiPredicate<Integer, Integer>() {
public boolean test(Integer i1, Integer i2) {
return Numbers.isMoreThanFifty(i1, i2);
}
};

// Using a lambda expression
BiPredicate<Integer, Integer> b = Numbers::isMoreThanFifty;

// Using a method reference
BiPredicate<Integer, Integer> c = (i1, i2) -> Numbers.isMoreThanFifty(i1, i2);

//i tre oggetti sono equivalenti
System.out.println(a.test(2, 3));
System.out.println(b.test(2, 3));
System.out.println(c.test(2, 3));

}
da notare che il metodo isMoreThanFifty ha bisogno di due parametri in input. Con il method reference non sono stati menzionati. Questo perche quando invochiamo il metodo test sull’istanza a.test(10,15), i parametri in input vengono passati in automatico al metodo Numbers.isMoreThanFifty(10, 15).

In generale la sintassi di un method reference può essere una delle seguenti:

NomeClasse::metodoIstanza // Il primo parametro è l’oggetto su cui è invocato
// il metodo e gli eventuali altri parametri sono
// passati al metodo
NomeClasse::metodoStatico // Tutti i parametri sono passati al metodo
oggetto::metodoIstanza // Tutti i parametri sono passati al metodo
E’ possibile anche invocare il costruttore con la stessa sintassi:
String:new

Esempio:

BiPredicate<String,String> eqstr = (s1,s2) -> s1.equals(s2);

con lambda diventa

BiPredicate<String,String> eqstr = String::equals;

eqstr.test(tmp, tmp2);

ossia il metodo equals sarà chiamato su tmp:

tmp.equals(tmp2);