Introduzione all'inferenza automatica dei tipi in Java
- A partire da JDK 10, Java supporta l'inferenza automatica dei tipi per le variabili locali, consentendo al compilatore di dedurre il tipo dalla dichiarazione inizializzatrice.
- L'inferenza di tipo delle variabili locali semplifica la scrittura del codice, riducendo la necessità di specificare esplicitamente i tipi quando possono essere dedotti.
- La parola chiave
var
viene utilizzata per dichiarare variabili locali con inferenza di tipo. - L'inferenza di tipo è sensibile al contesto e può essere utilizzata solo per variabili locali inizializzate.
Inferenza automatica dei tipi
Non molto tempo fa, è stata aggiunta al linguaggio Java una nuova funzionalità chiamata inferenza di tipo delle variabili locali.
Per cominciare, è opportuno rivedere due aspetti importanti delle variabili:
- In primo luogo, tutte le variabili in Java devono essere dichiarate prima di essere utilizzate.
- In secondo luogo, una variabile può essere inizializzata con un valore al momento della sua dichiarazione.
Inoltre, quando una variabile è inizializzata, il tipo dell'inizializzatore deve essere lo stesso (o almeno convertibile) del tipo dichiarato della variabile.
Pertanto, in linea di principio, non sarebbe necessario specificare esplicitamente il tipo di una variabile inizializzata perché potrebbe essere dedotto dal tipo del suo inizializzatore. In passato tale inferenza non era supportata e tutte le variabili richiedevano un tipo dichiarato esplicitamente, indipendentemente dal fatto che fossero inizializzate o meno. Oggi, la situazione è cambiata.
A partire da JDK 10 è possibile lasciare che il compilatore deduca il tipo di una variabile locale in base al tipo del suo inizializzatore, evitando così di specificare esplicitamente il tipo.
L'inferenza di tipo delle variabili locali offre diversi vantaggi. Ad esempio, può snellire il codice eliminando la necessità di specificare ridondantemente il tipo di una variabile quando questo può essere dedotto dal suo inizializzatore.
Può semplificare dichiarazioni in cui il nome del tipo è piuttosto lungo, come può accadere con alcuni nomi di classe. Può anche essere utile quando un tipo è difficile da individuare o non può essere denotato (un esempio è il tipo di una classe anonima, che vedremo in futuro).
Inoltre, l'inferenza di tipo delle variabili locali è ormai una componente comune dell'ambiente di programmazione contemporaneo. La sua inclusione in Java aiuta il linguaggio a restare al passo con le tendenze evolutive della progettazione dei linguaggi. Per supportare l'inferenza di tipo delle variabili locali è stata aggiunta la parola chiave sensibile al contesto var
.
Utilizzo di var
Per utilizzare l'inferenza di tipo delle variabili locali, la variabile deve essere dichiarata con var
come nome di tipo e deve includere un inizializzatore.
In passato si sarebbe dichiarata una variabile locale di tipo double
chiamata media
inizializzandola con il valore 10.0, come mostrato di seguito:
double media = 10.0;
Usando l'inferenza di tipo, questa dichiarazione può essere scritta anche così:
var media = 10.0;
In entrambi i casi, media
sarà di tipo double
. Nel primo caso il tipo è specificato esplicitamente. Nel secondo, il tipo è dedotto come double
perché l'inizializzatore 10.0
è di tipo double
.
Come accennato, var
è sensibile al contesto. Quando è impiegato come nome di tipo nel contesto di una dichiarazione di variabile locale, indica al compilatore di utilizzare l'inferenza di tipo per determinare il tipo della variabile in base al tipo dell'inizializzatore.
In una dichiarazione di variabile locale, var
funge quindi da segnaposto per il tipo reale dedotto.
Tuttavia, quando è usato nella maggior parte degli altri contesti, var
è semplicemente un identificatore definito dall'utente senza significato speciale. Ad esempio, la seguente dichiarazione è perfettamente valida:
int var = 1; // In questo caso, var è semplicemente un identificatore definito dall'utente.
Qui il tipo è specificato esplicitamente come int
e var
è il nome della variabile dichiarata. Benché sensibile al contesto, esistono alcuni casi in cui l'uso di var
è illegale: non può, ad esempio, essere usato come nome di una classe.
Il programma seguente mette in pratica la discussione precedente:
// Una semplice dimostrazione dell'inferenza di tipo delle variabili locali.
class DemoVar {
public static void main(String[] args) {
// Utilizza l'inferenza di tipo per determinare il tipo della
// variabile chiamata media. In questo caso viene dedotto double.
var media = 10.0;
System.out.println("Valore di media: " + media);
// Nel contesto seguente, var non è un identificatore predefinito.
// È semplicemente un nome di variabile definito dall'utente.
int var = 1;
System.out.println("Valore di var: " + var);
// È interessante notare che, nella sequenza seguente, var è utilizzato
// sia come tipo della dichiarazione sia come nome di variabile
// nell'inizializzatore.
var k = -var;
System.out.println("Valore di k: " + k);
}
}
Ecco l'output:
Valore di media: 10.0
Valore di var: 1
Valore di k: -1
L'esempio precedente utilizza var
per dichiarare solo variabili semplici, ma è anche possibile utilizzare var
per dichiarare un array. Ad esempio:
var mioArray = new int[10]; // Valido
Si noti che né var
né mioArray
presentano parentesi quadre. Il tipo di mioArray
viene infatti dedotto come int[]
. Non è inoltre possibile usare parentesi quadre sul lato sinistro di una dichiarazione con var
; pertanto, entrambe le dichiarazioni seguenti sono errate:
var[] mioArray = new int[10]; // Errato
var mioArray[] = new int[10]; // Errato
Nella prima riga si tenta di racchiudere var
tra parentesi quadre; nella seconda si tenta di racchiudere mioArray
. In entrambi i casi l'uso delle parentesi è scorretto perché il tipo viene dedotto dal tipo dell'inizializzatore.
È importante sottolineare che var
può essere usato per dichiarare una variabile solo quando quest'ultima è inizializzata. La seguente istruzione è perciò scorretta:
var contatore; // Errato! Inizializzatore richiesto.
Bisogna ricordare, inoltre, che var
può essere utilizzato esclusivamente per dichiarare variabili locali. Non può essere impiegato per dichiarare variabili di istanza, parametri o tipi restituiti.
Benché la discussione e gli esempi precedenti abbiano introdotto le basi dell'inferenza di tipo delle variabili locali, non ne hanno mostrato l'intera potenza. Vedremo che l'inferenza di tipo delle variabili locali è particolarmente efficace nell'accorciare dichiarazioni che coinvolgono nomi di classe lunghi. Può anche essere utilizzata con i tipi generici, in un'istruzione try-with-resources e con un ciclo for.
Alcune restrizioni su var
In aggiunta a quelle menzionate nella discussione precedente, si applicano diverse altre restrizioni all'uso di var
:
- È possibile dichiarare una sola variabile alla volta;
- una variabile non può usare
null
come inizializzatore; - la variabile dichiarata non può essere utilizzata dall'espressione di inizializzazione.
Sebbene sia possibile dichiarare un tipo di array usando var
, non si può usare var
con un inizializzatore di array. Ad esempio, questo è valido:
var mioArray = new int[10]; // Valido.
ma questo no:
var mioArray = { 1, 2, 3 }; // Errato
Come menzionato in precedenza, var
non può essere utilizzato come nome di una classe. Non può neppure essere utilizzato come nome di altri tipi reference, inclusi un'interfaccia, un'enumerazione o un'annotazione, né come nome di un parametro di tipo generico, tutti argomenti descritti più avanti in questa guida.
Ecco altre due restrizioni relative a funzionalità di Java descritte nelle lezioni successive ma riportate qui per completezza. L'inferenza del tipo di variabile locale non può essere utilizzata per dichiarare il tipo di eccezione catturato da un'istruzione catch
. Inoltre, né le espressioni lambda né i riferimenti a metodo possono essere utilizzati come inizializzatori.