1. Il problema dell instanceof classico
Cominciamo con un po’ di nostalgia. Prima di Java 16, quando bisognava verificare il tipo di un oggetto e poi usarlo come tale, occorreva scrivere un modello prolisso con il controllo instanceof e un cast esplicito:
Object obj = ...; // qualche oggetto
if (obj instanceof String) {
String s = (String) obj;
System.out.println("Lunghezza della stringa: " + s.length());
}
Noioso, ma frequente
Questo pattern ricorre molto spesso — gestori di eventi, lavoro con collezioni eterogenee, logica di business con ereditarietà ecc.
Perché è scomodo
- Duplicazione del codice — bisogna indicare il tipo due volte: sia in instanceof sia nel cast.
- Rischio di errore — è facile fare un cast al tipo sbagliato e ottenere ClassCastException.
- Codice «rumoroso» — peggiora la leggibilità, soprattutto con controlli multipli.
2. Pattern Matching per instanceof: nuova sintassi
In Java 16 è stato introdotto il pattern matching per instanceof. Ora si verifica il tipo e si dichiara subito una variabile del tipo richiesto, disponibile all’interno del ramo if.
Nuova sintassi
if (obj instanceof String s) {
// s è già una stringa!
System.out.println("Lunghezza della stringa: " + s.length());
}
- Dopo il tipo in instanceof si indica il nome della nuova variabile: String s.
- La variabile è disponibile solo all’interno del blocco in cui la condizione è vera.
- Non serve scrivere il cast (String) — ci pensa il compilatore.
Dov’è la magia? Il compilatore verifica il tipo e, se corrisponde, “espone” una variabile del tipo richiesto. Altrimenti il blocco semplicemente non viene eseguito.
Come appare nel codice reale
Object obj = "Ciao, Java 16+!";
if (obj instanceof String s) {
System.out.println("Maiuscolo: " + s.toUpperCase());
} else {
System.out.println("Non è una stringa!");
}
3. Sicurezza e leggibilità: perché è fantastico
Si elimina l’errore ClassCastException
Object obj = 123;
// String s = (String) obj; // Boom! Eccezione.
Con il pattern matching la variabile viene creata solo se il controllo del tipo ha successo — il cast “sbagliato” semplicemente non c’è.
Il codice diventa più breve e chiaro
Due righe diventano una. Meno codice «rumoroso» — più facile da leggere e mantenere.
Esempio: gestione di tipi diversi
public static void printInfo(Object obj) {
if (obj instanceof String s) {
System.out.println("Stringa di lunghezza " + s.length());
} else if (obj instanceof Integer i) {
System.out.println("Intero: " + (i + 1));
} else {
System.out.println("Tipo sconosciuto: " + obj);
}
}
4. Esempi d’uso e sfumature
Controllo di più tipi
Object value = ...;
if (value instanceof String s) {
System.out.println("È una stringa: " + s);
} else if (value instanceof Number n) {
System.out.println("È un numero: " + n);
} else {
System.out.println("Qualcos'altro: " + value);
}
Uso con null
Se l’oggetto è null, instanceof restituisce sempre false — niente NPE, ma il blocco non verrà eseguito.
Object obj = null;
if (obj instanceof String s) {
// Questo blocco NON verrà MAI eseguito se obj == null
System.out.println("Stringa: " + s);
} else {
System.out.println("obj è null oppure non è una stringa");
}
Pattern matching con l’ereditarietà
class Animal {}
class Dog extends Animal {
void bark() { System.out.println("Bau!"); }
}
Animal a = new Dog();
if (a instanceof Dog d) {
d.bark(); // Possiamo chiamare i metodi di Dog senza cast!
}
Ricordate: l’ordine dei controlli è importante: procedete dal più specifico al più generico, altrimenti i controlli «stretti» potrebbero non attivarsi.
Confronto: approccio vecchio e nuovo
| Metodo tradizionale | Nuovo metodo (pattern matching) |
|---|---|
|
|
5. Limitazioni del pattern matching per instanceof
- Ambito di visibilità della variabile. La variabile del pattern è visibile solo nel ramo in cui il controllo è vero.
if (obj instanceof String s) {
System.out.println(s); // s è disponibile
}
// System.out.println(s); // Errore! s non è visibile qui
- Non si possono dichiarare più variabili di tipi diversi in un’unica condizione.
// Errore di compilazione:
if (obj instanceof String s || obj instanceof Integer i) {
// ...
}
- Richiede Java 16+. Nelle versioni JDK più vecchie la nuova sintassi non è supportata.
6. Esempi pratici (basati su una semplice applicazione)
Immaginiamo un semplice Task Manager con diversi tipi di task.
Classi
class Task {
String title;
public Task(String title) { this.title = title; }
}
class BugTask extends Task {
int severity;
public BugTask(String title, int severity) {
super(title);
this.severity = severity;
}
}
class FeatureTask extends Task {
String feature;
public FeatureTask(String title, String feature) {
super(title);
this.feature = feature;
}
}
Elaborazione con pattern matching
public static void processTask(Task t) {
if (t instanceof BugTask bug) {
System.out.println("Bug: " + bug.title + ", gravità: " + bug.severity);
} else if (t instanceof FeatureTask feature) {
System.out.println("Feature: " + feature.title + ", modulo: " + feature.feature);
} else if (t instanceof Task task) {
System.out.println("Task normale: " + task.title);
}
}
7. Sfumature utili
Tabella: pattern matching per instanceof — pro e contro
| Pro | Contro/Limitazioni |
|---|---|
| Meno codice, maggiore leggibilità | Richiede Java 16+ |
| Nessun rischio di ClassCastException | La variabile è visibile solo all’interno del blocco if |
| Sicurezza dei tipi a livello di compilatore | Non funziona per più tipi in un’unica condizione |
| Comodo per gestire l’ereditarietà | Potrebbe non essere supportato in IDE/build vecchi |
| Adatto a qualsiasi classe |
Schema visivo: come funziona il pattern matching per instanceof
+---------------------------+
| Object obj |
+---------------------------+
|
v
if (obj instanceof Type t)
|
Sì No
(true) (false)
| |
v v
t disponibile t non esiste
(codice) (nessun accesso)
8. Errori tipici nell’uso del pattern matching per instanceof
Errore n. 1: tentativo di usare la variabile fuori dal blocco if. La variabile è stata dichiarata nel pattern, si esce dal blocco — la variabile non esiste più. Il compilatore protesta giustamente: «Chi è s?»
Errore n. 2: aspettarsi che instanceof funzioni con null. Se l’oggetto è null, la condizione instanceof è sempre falsa, la variabile non viene creata. Gestite null separatamente se necessario.
Errore n. 3: usare la nuova sintassi su una versione JDK/IDE vecchia. In Java 11 e inferiori il pattern matching per instanceof non è disponibile — otterrete un errore di sintassi. Verificate la versione della JDK.
Errore n. 4: confusione sullo scope. La variabile del pattern è disponibile solo nel ramo in cui il controllo è vero. Fuori da lì — non esiste.
Errore n. 5: aspettarsi il supporto di più tipi contemporaneamente. Non è possibile dichiarare due variabili di tipi diversi in un’unica condizione: if (obj instanceof String s || obj instanceof Integer i) — non si può. Per ogni tipo serve un controllo a parte.
GO TO FULL VERSION