Espressioni Lambda e Cattura di Variabili in Java
- Le espressioni lambda in Java possono catturare variabili locali, ma solo se sono effettivamente
final
. - Una variabile effettivamente
final
è una variabile il cui valore non cambia dopo essere stata assegnata per la prima volta. - Le espressioni lambda hanno accesso a variabili di istanza e statiche della loro classe di inclusione, ma non possono modificare variabili locali a meno che non siano effettivamente
final
. - La cattura di variabili consente alle espressioni lambda di accedere a variabili definite nell'ambito di inclusione, migliorando la flessibilità e l'espressività del codice.
Cattura di Variabili nelle Espressioni Lambda
Le variabili definite dall'ambito di inclusione di un'espressione lambda sono accessibili all'interno dell'espressione lambda.
Ad esempio, un'espressione lambda può utilizzare una variabile di istanza o static
definita dalla sua classe di inclusione. Un'espressione lambda ha anche accesso a this
(sia esplicitamente che implicitamente), che si riferisce all'istanza invocante della classe di inclusione dell'espressione lambda. Pertanto, un'espressione lambda può ottenere o impostare il valore di una variabile di istanza o static
e chiamare un metodo definito dalla sua classe di inclusione.
Tuttavia, quando un'espressione lambda utilizza una variabile locale dal suo ambito di inclusione, si crea una situazione speciale che viene chiamata cattura di variabile.
In questo caso, un'espressione lambda può utilizzare solo variabili locali che sono effettivamente final
. Una variabile effettivamente final
è una variabile il cui valore non cambia dopo essere stata assegnata per la prima volta. Non è necessario dichiarare esplicitamente tale variabile come final
, anche se farlo non sarebbe un errore. Il parametro this
di un ambito di inclusione è automaticamente effettivamente final
, e le espressioni lambda non hanno un proprio this
.
È importante comprendere che una variabile locale dell'ambito di inclusione non può essere modificata dall'espressione lambda. Farlo rimuoverebbe il suo status di effettivamente final
, rendendola quindi illegale per la cattura.
Il seguente programma illustra la differenza tra variabili locali effettivamente final
e mutabili:
// Esempio di cattura di una variabile locale dall'ambito di inclusione.
// Un'interfaccia funzionale che dichiara il metodo funzione().
interface MiaFunzione {
// Il metodo funzione() accetta un intero e restituisce un intero.
int func(int n);
}
// Una classe che dimostra la cattura di variabili locali.
class CatturaVariabili {
public static void main(String[] args) {
// Una variabile locale che può essere catturata.
int numero = 10;
// Un'espressione lambda che cattura la variabile numero.
MiaFunzione mioLambda = (n) -> {
// Questo uso di numero è OK. Non modifica numero.
int v = numero + n;
// Tuttavia, il seguente è illegale perché tenta
// di modificare il valore di numero.
// numero++;
return v;
};
// Chiamata al lambda con un argomento.
int risultato = mioLambda.func(5);
// Stampa: Risultato: 15
System.out.println("Risultato: " + risultato);
// La seguente riga causerebbe anche un errore, perché
// rimuoverebbe lo status effettivamente final da numero.
// In altre parole, non è possibile modificare numero qui.
// numero = 9;
}
}
Come indicano i commenti, numero
è effettivamente final
e può, pertanto, essere utilizzata all'interno di mioLambda
. Tuttavia, se numero
fosse modificata, sia all'interno del lambda che al di fuori di esso, numero
perderebbe il suo status effettivamente final
. Questo causerebbe un errore, e il programma non compilerebbe.
È importante sottolineare che un'espressione lambda può utilizzare e modificare una variabile di istanza dalla sua classe invocante. Semplicemente non può utilizzare una variabile locale del suo ambito di inclusione a meno che quella variabile non sia effettivamente final
.