Espressioni Lambda e Eccezioni in Java

Concetti Chiave
  • Le espressioni lambda in Java possono lanciare eccezioni, ma le eccezioni controllate devono essere compatibili con la clausola throws del metodo nell'interfaccia funzionale.
  • È possibile definire eccezioni personalizzate e utilizzarle all'interno delle espressioni lambda.

Espressioni Lambda ed Eccezioni

Un'espressione lambda può lanciare un'eccezione.

Tuttavia, se lancia un'eccezione controllata, allora quell'eccezione deve essere compatibile con le eccezioni elencate nella clausola throws del metodo astratto nell'interfaccia funzionale.

Ecco un esempio che illustra questo fatto. Questo esempio calcola la media di un array di valori double. Se viene passato un array di lunghezza zero, tuttavia, lancia l'eccezione personalizzata EccezioneArrayVuoto.

Come mostra l'esempio, questa eccezione è elencata nella clausola throws di funzione() dichiarata all'interno dell'interfaccia funzionale FunzioneArrayNumericoDouble.

// Lancia un'eccezione da un'espressione lambda.

// Un'interfaccia funzionale che dichiara il metodo funzione().
// Questa interfaccia funzionale accetta un array di double e
// restituisce un double.
// Il metodo funzione() può lanciare un'eccezione
// EccezioneArrayVuoto.
interface FunzioneArrayNumericoDouble {
    double funzione(double[] n) throws EccezioneArrayVuoto;
}

// Un'eccezione personalizzata che viene lanciata quando
// viene passato un array di lunghezza zero.
class EccezioneArrayVuoto extends Exception {
    EccezioneArrayVuoto() {
        super("Array Vuoto");
    }
}

// Una classe che dimostra l'uso di un'espressione lambda
// che lancia un'eccezione.
class DemoEccezioniLambda {

    public static void main(String[] args) throws EccezioneArrayVuoto
    {
        double[] valori = { 1.0, 2.0, 3.0, 4.0 };

        // Questa lambda a blocco calcola la media di un array di double.
        FunzioneArrayNumericoDouble media = (n) -> {
            double somma = 0;
            if(n.length == 0)
                throw new EccezioneArrayVuoto();
            for(int i=0; i < n.length; i++)
                somma += n[i];
            return somma / n.length;
        };

        // Questa istruzione calcola la media di un array di valori double.
        System.out.println("La media è " +
                           media.funzione(valori));
        // Questo causa il lancio di un'eccezione.
        System.out.println("La media è " +
                           media.funzione(new double[0]));
    }

}

L'esecuzione di questo programma produce il seguente output:

La media è 2.5
Exception in thread "main" EccezioneArrayVuoto: Array Vuoto
        at DemoEccezioniLambda.lambda$main$0(DemoEccezioniLambda.java:32)
        at DemoEccezioniLambda.main(DemoEccezioniLambda.java:43)

La prima chiamata a media.funzione() restituisce il valore 2.5. La seconda chiamata, che passa un array di lunghezza zero, causa il lancio di un'EccezioneArrayVuoto.

Bisogna ricordare che l'inclusione della clausola throws in funzione() è necessaria. Senza di essa, il programma non si compilerà perché l'espressione lambda non sarà più compatibile con funzione().

Questo esempio dimostra un altro punto importante sulle espressioni lambda. Si noti che il parametro specificato da funzione() nell'interfaccia funzionale FunzioneArrayNumericoDouble è un array.

Tuttavia, il parametro dell'espressione lambda è semplicemente n, piuttosto che n[ ].

Bisogna ricordare che il tipo di un parametro di un'espressione lambda sarà dedotto dal contesto di destinazione. In questo caso, il contesto di destinazione è double[ ], quindi il tipo di n sarà double[ ]. Non è necessario (né legale) specificarlo come n[ ]. Sarebbe legale dichiararlo esplicitamente come double[ ] n, ma farlo non porta alcun vantaggio in questo caso.