Espressioni Lambda con Corpo a Blocco in Java

Concetti Chiave
  • Le espressioni lambda in Java possono avere un corpo a blocco, che consente di utilizzare più istruzioni all'interno della lambda.
  • Le lambda a blocco richiedono l'uso esplicito dell'istruzione return per restituire un valore.
  • Le lambda a blocco possono contenere variabili, cicli, istruzioni if e switch, e altri costrutti di controllo del flusso.
  • Le lambda a blocco sono simili ai metodi in termini di struttura, ma non restituiscono il controllo al metodo che le contiene quando viene utilizzata l'istruzione return.

Espressioni Lambda con Corpo

Nella lezione precedente, in cui abbiamo introdotto le espressioni lambda, ci siamo limitati a studiare lambda con un corpo costituito da una singola espressione.

Questi tipi di corpi lambda sono chiamati corpi di espressione e le lambda che hanno corpi di espressione sono talvolta chiamate espressioni lambda.

In un corpo di espressione, il codice sul lato destro dell'operatore lambda deve consistere di una singola espressione. Mentre le espressioni lambda sono molto utili, a volte la situazione richiederà più di una singola espressione.

Per gestire tali casi, Java supporta un secondo tipo di espressione lambda in cui il codice sul lato destro dell'operatore lambda consiste di un blocco di codice che può contenere più di un'istruzione. Questo tipo di corpo lambda è chiamato corpo a blocco. Le lambda che hanno corpi a blocco sono talvolta chiamate lambda a blocco.

Una lambda a blocco espande i tipi di operazioni che possono essere gestite all'interno di un'espressione lambda perché permette al corpo della lambda di contenere istruzioni multiple. Per esempio, in una lambda a blocco è possibile dichiarare variabili, usare cicli, specificare istruzioni if e switch, creare blocchi annidati, e così via. Una lambda a blocco è facile da creare. Semplicemente si tratta di racchiudere il corpo tra parentesi graffe come faremmo con qualsiasi altro blocco di istruzioni.

Oltre a permettere istruzioni multiple, le lambda a blocco sono usate molto simili alle lambda di espressione appena discusse. Una differenza chiave, tuttavia, è che bisogna usare esplicitamente un'istruzione return per restituire un valore. Questo è necessario perché un corpo lambda a blocco non rappresenta una singola espressione.

Ecco un esempio che usa una lambda a blocco per calcolare e restituire il fattoriale di un valore int:

// Una lambda a blocco che calcola il fattoriale di un valore int.

// Un'interfaccia funzionale che dichiara il metodo funzione().
interface FunzioneNumerica {
    int funzione(int n);
}

class DemoLambdaBlocco {

    public static void main(String[] args)
    {
        // Questa lambda a blocco calcola il fattoriale di un valore int.
        FunzioneNumerica fattoriale = (n) -> {
            int risultato = 1;
            for(int i=1; i <= n; i++)
                risultato = i * risultato;
            return risultato;
        };

        // Usiamo la lambda a blocco per calcolare il fattoriale di 3 e 5.
        System.out.println("Il fattoriale di 3 è " + fattoriale.funzione(3));
        System.out.println("Il fattoriale di 5 è " + fattoriale.funzione(5));
    }

}

L'output è mostrato qui:

Il fattoriale di 3 è 6
Il fattoriale di 5 è 120

Nel programma, si noti che la lambda a blocco dichiara una variabile chiamata risultato, usa un ciclo for, e ha un'istruzione return. Queste istruzioni sono legali all'interno di un corpo lambda a blocco. In sostanza, il corpo a blocco di una lambda è simile a un corpo di metodo.

Un altro punto: quando un'istruzione return si presenta all'interno di un'espressione lambda, semplicemente causa un ritorno dalla lambda. Non causa il ritorno di un metodo che la racchiude.

Un altro esempio di una lambda a blocco è mostrato nel seguente programma. Inverte i caratteri in una stringa.

// Una lambda a blocco che inverte i caratteri in una stringa.

// Un'interfaccia funzionale che dichiara il metodo funzione().
interface FunzioneStringa {
    String funzione(String n);
}

class DemoLambdaBlocco2 {

    public static void main(String[] args)
    {
        // Questa lambda a blocco inverte i caratteri in una stringa.
        FunzioneStringa inverti = (str) -> {
            String risultato = "";
            int i;
            for(i = str.length()-1; i >= 0; i--)
                risultato += str.charAt(i);
            return risultato;
        };

        // Usiamo la lambda a blocco per invertire
        // le stringhe "Lambda" ed "Espressione".
        System.out.println("Lambda invertita è " +
                           inverti.funzione("Lambda"));
        System.out.println("Espressione invertita è " +
                           inverti.funzione("Espressione"));
    }

}

L'output è mostrato qui:

Lambda invertita è adbmaL
Espressione invertita è enoisserpxE

In questo esempio, l'interfaccia funzionale FunzioneStringa dichiara il metodo funzione(). Questo metodo prende un parametro di tipo String e ha un tipo di ritorno String. Così, nell'espressione lambda inverti, il tipo di str è inferito essere String. Si noti che il metodo charAt() è chiamato su str. Questo è legale a causa dell'inferenza che str è di tipo String.