CodeGym /Corsi /JAVA 25 SELF /Gerarchia delle eccezioni in Java

Gerarchia delle eccezioni in Java

JAVA 25 SELF
Livello 24 , Lezione 0
Disponibile

1. Classe Throwable: la radice di tutte le eccezioni

Ora analizziamo in dettaglio come è strutturato il sistema delle eccezioni in Java: che cos’è Throwable, in cosa differiscono Exception ed Error, e che cosa significano eccezioni «controllate» e «non controllate». È il fondamento per una corretta gestione degli errori nelle vostre applicazioni.

In Java tutte le eccezioni e gli errori sono oggetti che derivano dalla classe java.lang.Throwable.
Throwable è il «capostipite» dell’intera gerarchia per la gestione dei problemi in Java.

Schematicamente:

Throwable
├── Exception
└── Error

Throwable è la classe base per tutto ciò che può essere «lanciato» (throw) e «catturato» (catch) in Java. Non si usa direttamente: funge da base per tipi di errore più specifici.

Exception – per errori «normali»

Exception è la classe base per tutte le eccezioni che possono verificarsi in un programma e che si possono e si devono gestire. Sono errori «operativi»: problemi con file, rete, I/O, input dell’utente, ecc. La maggior parte dei vostri try-catch lavorerà proprio con i discendenti di Exception.

Esempi:

  • IOException – errore durante l’accesso a file o rete.
  • SQLException – errore durante il lavoro con il database.
  • FileNotFoundException – file non trovato.

Error – per errori fatali della JVM

Error è la classe base per errori che avvengono a livello di Java Virtual Machine (JVM). Di solito sono guasti critici che il programma non può e non dovrebbe gestire. Se si verifica un Error, molto probabilmente l’applicazione non potrà proseguire.

Esempi:

  • OutOfMemoryError – memoria esaurita.
  • StackOverflowError – overflow dello stack (ad esempio a causa di ricorsione infinita).
  • NoClassDefFoundError – classe necessaria non trovata.

Importante:
Catturare e gestire Error è quasi sempre una cattiva idea. Non sono errori del vostro programma, ma guasti dell’ambiente di esecuzione.

2. Checked vs unchecked exceptions: che cosa significa?

In Java tutte le eccezioni si dividono in due grandi gruppi:

Eccezioni controllate (Checked)

Che cosa sono? Eccezioni che il compilatore impone di gestire o di propagare esplicitamente.

Quando si verificano? Di solito sono legate a risorse esterne: file, rete, database, input dell’utente.

Come gestirle? Occorre racchiudere il codice in try-catch oppure aggiungere throws alla firma del metodo.

Esempi: IOException, SQLException, FileNotFoundException

Esempio:

public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path); // può generare IOException
    // ...
}

Se non le gestisci o non le propaghi, il programma non verrà compilato!

Eccezioni non controllate (Unchecked)

Che cosa sono? Eccezioni che non richiedono gestione obbligatoria da parte del compilatore.

Quando si verificano? Di solito sono errori nella logica del programma: divisione per zero, uscita dai limiti dell’array, accesso a null.

Come gestirle? Si possono catturare, ma non è obbligatorio. È meglio prevenire tali errori con opportune verifiche.

Dove nella gerarchia? Tutte discendono da RuntimeException.

Esempi: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException

Esempio:

int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException

Il compilatore non obbliga a catturare questa eccezione, ma l’applicazione si arresterà in caso di errore.

3. L’intera gerarchia in un’unica figura

graph TD
    Throwable --> Error
    Throwable --> Exception
    
    Exception --> RuntimeException
    Exception --> CheckedExceptions["(altre eccezioni checked)"]
    
    Error --> OutOfMemoryError
    Error --> StackOverflowError
    
    RuntimeException --> NullPointerException
    RuntimeException --> IndexOutOfBoundsException
    RuntimeException --> IllegalArgumentException

    %% Stili
    style Throwable fill:#ffa64d,color:#000
    style Exception fill:#ffa64d,color:#000
    style CheckedExceptions fill:#ffa64d,color:#000
    
    style Error fill:#ff4d4d,color:#fff
    style OutOfMemoryError fill:#ff4d4d,color:#fff
    style StackOverflowError fill:#ff4d4d,color:#fff
    
    style RuntimeException fill:#4dff88,color:#000
    style NullPointerException fill:#4dff88,color:#000
    style IndexOutOfBoundsException fill:#4dff88,color:#000
    style IllegalArgumentException fill:#4dff88,color:#000

Tabella: differenze principali

Gruppo Classe base Richiede gestione? Esempi
Checked Exception
Exception
IOException, SQLException
Unchecked
RuntimeException
No
NullPointerException, IndexOutOfBoundsException
Error
Error
No
OutOfMemoryError, StackOverflowError

4. Come appare nel codice?

Checked exception: esempio con i file

import java.io.*;

public class FileDemo {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("nofile.txt"); // FileNotFoundException (checked)
            int data = reader.read();
            System.out.println(data);
            reader.close();
        } catch (IOException e) {
            System.out.println("Errore durante l'operazione sul file: " + e.getMessage());
        }
    }
}

Il compilatore ti obbligherà a gestire IOException!

Unchecked exception: esempio con divisione per zero

public class ExceptionDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int c = a / b; // ArithmeticException (unchecked)
        System.out.println("Risultato: " + c);
    }
}

Il compilatore non richiede la gestione, ma il programma si arresterà.

5. Perché serve la gerarchia delle eccezioni?

  • Flessibilità di gestione: È possibile catturare sia errori specifici (FileNotFoundException) sia intere famiglie (IOException o Exception).
  • Riutilizzo del codice: Si possono gestire centralmente errori dello stesso tipo.
  • Pulizia del codice: La logica principale non viene appesantita da controlli per ogni minimo dettaglio.

Esempio:

try {
    // codice rischioso
} catch (FileNotFoundException e) {
    System.out.println("File non trovato!");
} catch (IOException e) {
    System.out.println("Errore di I/O!");
} catch (Exception e) {
    System.out.println("Qualcosa è andato storto: " + e.getMessage());
}

6. Errori tipici nella gestione delle eccezioni

Errore n. 1: ignorare le eccezioni. Scrivere catch (Exception e) {} – è una cattiva pratica! Perdi informazioni sulla causa del problema.

Errore n. 2: si cattura troppo. catch (Exception e) cattura tutto, anche ciò che non ti aspetti. Meglio catturare solo le eccezioni che sai gestire.

Errore n. 3: si catturano gli Error. Non dovresti catturare Error, a meno che tu non stia scrivendo codice di basso livello. Sono problemi della JVM, non della tua applicazione.

Errore n. 4: non distinguere tra checked e unchecked. Non tutte le eccezioni sono uguali! Le checked richiedono gestione (Exception), le unchecked no (RuntimeException e discendenti).

Errore n. 5: non aggiungere informazioni alle eccezioni. Se crei eccezioni personalizzate, aggiungi sempre un messaggio informativo.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION