Java 8 – Parte 1 – Perché abbiamo bisogno del Lambda calcolo in Java?

Questo è il primo di una serie di articoli su Java 8. In questa serie di articoli analizzeremo alcune nuove caratteristiche del linguaggio e come utilizzarle al meglio.

Per un programmatore che ha esperienza con Java, sarà ormai chiaro che Java si sta avvicinando al paradigma funzionale. L’elevata espressività di un paradigma funzionale ci consentirà di migliorare il nostro codice  e soprattutto approcciare in maniera differente alcune problematiche.

Espressioni Lambda – λ-calcolo

Esempio confronto con lambda calcolo in Java

Chi ha già famigliarità con le chiusure (closure) non sta leggendo nulla di nuovo.

Una espressione Lambda è una funzione anonima che può essere passata come argomento o restituita in uscita nei metodi. É una feature molto comune per alcuni linguaggi di programmazione come Lisp, Python, Scala, Groovy, …

Prima di Java 8 se volevamo passare un blocco di codice per essere eseguito, dovevamo creare un oggetto con un metodo e passarlo, un po’ come si fa per il design pattern Strategy. In Java 8, le espressioni lambda ci permettono di considerare una funzione come un argomento di un metodo e passare dei “pezzi di codice”. Sono una componente del linguaggio molto potente e irresistibili :). In questo articolo svilupperemo un piccolo esempio di programmazione funzionale in Java 8.

Ordinamento prima di Java 8

L’esempio che segue mostra come usare un Comparator per ordinare una lista di oggetti.

Definiamo una classe Employee:

public class Employee {

    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }

    public void setAge(int age) { this.age = age; }

    @Override
    public String toString() {
        return "Employee{" + "name=" + name + ", age=" + age + '}';
    }
}

Instanziamo una lista di impiegati (oggetti della classe Employee):

List employees = new ArrayList<>();
employees.add(new Employee("Andrea", 24));
employees.add(new Employee("Stefano", 20));
employees.add(new Employee("Loris", 25));
employees.add(new Employee("Davide", 18));

Se adesso desideriamo ordinare questa lista è possibile usare il metodo statico sort della classe Collections (JDK7), dichiarato come segue:

sort(List list, Comparator c)

Senza addentrarci tanto nel dettaglio (immagino che già abbiate una buona conoscenza di Java), il metodo richiede come parametro la lista e l’istanza di un oggetto che implementa l’interfaccia Comparator. Questa interfaccia richiede che venga implementato il seguente metodo:

int compare(T o1, T o2);

Il Javadoc di questo metodo indica che il metodo confronta i due argumenti e deve ritornare un numero negativo, zero o positivo ad indicare se il primo argomento è minore, uguale o maggiore del secondo.

Se volessimo ordinare la lista di Employee per età, dobbiamo definire una classe che implementa l’interfaccia Comparator in maniera corretta:

    private class EmployeeComparator implements Comparator {
        @Override
        public int compare(Employee o1, Employee o2) {
            return o1.getAge() - o2.getAge();
        }
    }

e poi passarlo nelo metodo sort. O più comodamente possiamo fare tutto insieme usando le classi anonime:

        Collections.sort(employees, new Comparator() {
            @Override
            public int compare(Employee o1, Employee o2) {
                return o1.getAge() - o2.getAge();
            }
        });

Non è complicato, si tratta di un elegante Strategy pattern, ma converrete con me che è abbastanza prolisso.

Ordinamento con espressioni Lambda

In Java 8 le cose diventano molto più semplici e immediate. Non è necessario definire una classe anonima che implementa un metodo che poi passeremo come argomento, come è stato fatto nell’esempio precedente. É sufficiente dichiarare la funzione nell’argomento del metodo sort.

Collections.sort(employees, (o1, o2) -> o1.getAge() - o2.getAge());

(in Java 8 volendo possiamo usare direttamente il metodo sort ereditato da List).

(o1, o2) -> o1.getAge() – o2.getAge() è una espressione Lambda. Dietro le scene è convertita in un oggetto Comparator. Per ora limitiamoci a considerare queste espressioni semplicemente come funzioni. Come vengono converite in oggetti di interfacce funzionali è qualcosa che analizzeremo negli articoli che seguiranno.

Conclusioni

Questa è solo una breve introduzione per mostrare la potenza e la versatilità del Lambda calcolo in un esempio banale. Gli articoli che seguiranno mostreranno la sintassi delle espressioni Lambda, quando usarle, casi avanzati d’uso e consigli per il refactoring del vostro codice.

Happy coding…

Un commento su “Java 8 – Parte 1 – Perché abbiamo bisogno del Lambda calcolo in Java?”

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *