CodeGym /Corsi /JAVA 25 SELF /Gestione complessa delle eccezioni e best practice

Gestione complessa delle eccezioni e best practice

JAVA 25 SELF
Livello 24, Lezione 3
Disponibile

1. catch multipli: gestione di eccezioni diverse

Nelle applicazioni reali lo stesso blocco di codice può generare diversi tipi di eccezioni. Ad esempio, durante la lettura di un file può verificarsi sia FileNotFoundException sia IOException, e durante il parsing dei dati — anche NumberFormatException. Per gestire correttamente ogni situazione, in Java è possibile usare più blocchi catch in sequenza.

Sintassi

try {
    // operazioni rischiose
} catch (FileNotFoundException e) {
    System.out.println("File non trovato: " + e.getMessage());
} catch (IOException e) {
    System.out.println("Errore di I/O: " + e.getMessage());
} catch (NumberFormatException e) {
    System.out.println("Formato del numero non valido: " + e.getMessage());
}

Punto importante:
I blocchi catch devono andare dal più specifico al più generale! Se si scrive prima catch (Exception e), tutti gli altri blocchi diventeranno irraggiungibili e il compilatore segnalerà un errore.

Perché è importante?

  • Gestione specifica: È possibile reagire in modo diverso a errori differenti (ad esempio, proporre di scegliere un altro file o ripetere l'input).
  • Leggibilità: Il codice diventa più chiaro — è evidente quali errori sono previsti e come vengono gestiti.

2. catch con più tipi (multi-catch)

A volte per eccezioni diverse è necessaria la stessa gestione. Ad esempio, vuoi solo mostrare un messaggio di errore o registrarlo nel log, indipendentemente dal fatto che si tratti di un errore di lettura del file o di conversione del numero.

A partire da Java 7 è stata introdotta la sintassi multi-catch, che consente di unire più tipi di eccezioni in un unico blocco:

try {
    // operazione rischiosa
} catch (IOException | NumberFormatException e) {
    System.out.println("Errore durante l'elaborazione del file o del numero: " + e.getMessage());
}

Come funziona:

  • I tipi di eccezione sono indicati separandoli con la barra verticale (|).
  • La variabile e avrà il tipo della superclasse comune più generale (di solito Exception).
  • All'interno del blocco non è consentito assegnare un nuovo valore alla variabile e — è considerata final automaticamente.

Esempio:

try {
    BufferedReader reader = new BufferedReader(new FileReader("numbers.txt"));
    String line = reader.readLine();
    int number = Integer.parseInt(line);
    System.out.println("Numero: " + number);
    reader.close();
} catch (IOException | NumberFormatException e) {
    System.out.println("Errore: " + e.getMessage());
}

3. Best practice per la gestione delle eccezioni

Non sopprimere le eccezioni

Sbagliato:

try {
    // qualcosa di rischioso
} catch (Exception e) {
    // non facciamo nulla!
}

Perché è sbagliato?
Un blocco catch vuoto “sopprime” l'errore — perdi informazioni sulla causa del problema e il programma diventa difficile da diagnosticare.

Meglio: almeno stampa un messaggio o registra l'errore nel log.

catch (Exception e) {
    e.printStackTrace();
}

Se non puoi gestire l'eccezione — rilanciala più in alto:

catch (IOException e) {
    throw e; // oppure throw new RuntimeException(e);
}

Lancia eccezioni il più specifiche possibile

Se stai scrivendo i tuoi metodi o API, lancia sempre eccezioni quanto più specifiche, e non semplicemente Exception o RuntimeException. Questo rende il tuo codice e l'interfaccia più chiari per gli altri sviluppatori.

Esempio:

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("Fondi insufficienti");
    }
    // ...
}

Non usare le eccezioni per controllare il flusso del programma

Le eccezioni sono pensate per gestire situazioni eccezionali, cioè errori che non dovrebbero verificarsi nel normale funzionamento del programma. Non usarle per la logica ordinaria (ad esempio per uscire da un ciclo o per verificare condizioni).

Sbagliato:

try {
    while (true) {
        String line = reader.readLine();
        if (line == null) break;
        // elaborazione della riga
    }
} catch (Exception e) {
    // usare un'eccezione per uscire dal ciclo — sbagliato!
}

Corretto:

String line;
while ((line = reader.readLine()) != null) {
    // elaborazione della riga
}

4. Esempi pratici

Esempio: gestire errori diversi in modo diverso

try {
    BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
    String line = reader.readLine();
    int number = Integer.parseInt(line);
    System.out.println("Numero: " + number);
    reader.close();
} catch (FileNotFoundException e) {
    System.out.println("File non trovato!");
} catch (IOException e) {
    System.out.println("Errore di lettura del file!");
} catch (NumberFormatException e) {
    System.out.println("Il file non contiene un numero!");
}

Esempio: multi-catch per la stessa gestione

try {
    // qualcosa di rischioso
} catch (IOException | NumberFormatException e) {
    System.out.println("Errore: " + e.getMessage());
}

5. Aspetti importanti ed errori tipici

Errore n. 1: ordine errato dei blocchi catch. Prima devono venire le eccezioni più specifiche e poi quelle generali. Altrimenti l'esecuzione non raggiungerà mai il blocco più ampio.

Errore n. 2: utilizzo di tipi correlati in un multi-catch. Ad esempio, catch (IOException | Exception e) non verrà compilato, perché IOException estende Exception.

Errore n. 3: tentativo di modificare la variabile e in un multi-catch. In questo caso e è considerata final — non è possibile assegnarle un nuovo valore.

Errore n. 4: blocchi catch vuoti. Ignorare gli errori porta a bug “silenziosi”. Al minimo — stampa un messaggio o registra l'eccezione nel log.

Errore n. 5: catturare tutte le Exception indiscriminatamente. L'uso di catch (Exception e) nasconde i problemi reali e rende più difficile il debug. Meglio catturare solo le eccezioni previste.

1
Compito
JAVA 25 SELF, livello 24, lezione 3
Bloccato
Rapporto finanziario: Diagnosi precisa dei problemi con i dati
Rapporto finanziario: Diagnosi precisa dei problemi con i dati
1
Compito
JAVA 25 SELF, livello 24, lezione 3
Bloccato
Impostazioni del gioco: Reazione unificata ai guasti di caricamento
Impostazioni del gioco: Reazione unificata ai guasti di caricamento
1
Compito
JAVA 25 SELF, livello 24, lezione 3
Bloccato
Archivio segreto: Priorità di accesso ai documenti riservati
Archivio segreto: Priorità di accesso ai documenti riservati
1
Compito
JAVA 25 SELF, livello 24, lezione 3
Bloccato
Servizio di logging: Nessun errore deve andare perso!
Servizio di logging: Nessun errore deve andare perso!
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION