Java Language La gerarchia delle eccezioni Java - Eccezioni non selezionate e controllate


Esempio

Tutte le eccezioni Java sono istanze di classi nella gerarchia di classi Exception. Questo può essere rappresentato come segue:

  • java.lang.Throwable - Questa è la classe base per tutte le classi di eccezioni. I suoi metodi e costruttori implementano una gamma di funzionalità comuni a tutte le eccezioni.
    • java.lang.Exception - Questa è la superclasse di tutte le normali eccezioni.
      • varie classi di eccezioni standard e personalizzate.
      • java.lang.RuntimeException - Questa è la superclasse di tutte le eccezioni normali che sono eccezioni non controllate .
        • varie classi di eccezioni di runtime standard e personalizzate.
    • java.lang.Error - Questa è la superclasse di tutte le eccezioni di "errore fatale".

Gli appunti:

  1. La distinzione tra le eccezioni controllate e non controllate è descritta di seguito.
  2. La Throwable , Exception e RuntimeException deve essere considerata abstract ; vedi Pitfall - Throwable Throwable, Exception, Error o RuntimeException .
  3. Le eccezioni di Error vengono generate dalla JVM in situazioni in cui non sarebbe sicuro o imprudente per un'applicazione tentare di ripristinare.
  4. Non sarebbe saggio dichiarare sottotipi personalizzati di Throwable . Gli strumenti e le librerie Java possono assumere che Error ed Exception sono gli unici sottotipi diretti di Throwable e si comportano Throwable se tale presupposto non è corretto.

Controllato contro Eccezioni non selezionate

Una delle critiche al supporto delle eccezioni in alcuni linguaggi di programmazione è che è difficile sapere quali eccezioni potrebbero generare un determinato metodo o procedura. Dato che un'eccezione non gestita può causare l'arresto anomalo di un programma, ciò può rendere le eccezioni una fonte di fragilità.

Il linguaggio Java affronta questo problema con il meccanismo di eccezione verificato. Innanzitutto, Java classifica le eccezioni in due categorie:

  • Le eccezioni controllate rappresentano in genere gli eventi previsti che un'applicazione dovrebbe essere in grado di gestire. Ad esempio, IOException e i suoi sottotipi rappresentano condizioni di errore che possono verificarsi nelle operazioni di I / O. Gli esempi includono, l'apertura di file non avviene perché un file o una directory non esiste, le letture e le scritture di rete non funzionano perché una connessione di rete è stata interrotta e così via.

  • Le eccezioni non controllate tipicamente rappresentano eventi imprevisti che un'applicazione non è in grado di gestire. Questi sono in genere il risultato di un bug nell'applicazione.

(Di seguito, "gettato" si riferisce a qualsiasi eccezione lanciata esplicitamente (da un'istruzione throw ), o implicitamente (in un dereferenziamento fallito, digitare cast e così via). Allo stesso modo, "propagated" si riferisce a un'eccezione che è stata lanciata in un chiamata nidificata e non catturata all'interno di quella chiamata. Il seguente codice di esempio illustrerà questo.)

La seconda parte del meccanismo di eccezione verificata è che esistono restrizioni sui metodi in cui può verificarsi un'eccezione verificata:

  • Quando un'eccezione controllata viene lanciata o propagata in un metodo, deve essere rilevata dal metodo o elencata nella clausola di throws del metodo. (Il significato della clausola throws è descritto in questo esempio ).
  • Quando un'eccezione controllata viene lanciata o propagata in un blocco di inizializzazione, deve essere catturata dal blocco.
  • Un'eccezione verificata non può essere propagata da una chiamata di metodo in un'espressione di inizializzazione del campo. (Non c'è modo di cogliere tale eccezione).

In breve, un'eccezione controllata deve essere gestita o dichiarata.

Queste restrizioni non si applicano alle eccezioni non controllate. Ciò include tutti i casi in cui un'eccezione viene lanciata implicitamente, poiché tutti questi casi generano eccezioni non controllate.

Esempi di eccezioni controllati

Questi snippet di codice hanno lo scopo di illustrare le restrizioni delle eccezioni controllate. In ogni caso, mostriamo una versione del codice con un errore di compilazione e una seconda versione con l'errore corretto.

// This declares a custom checked exception.
public class MyException extends Exception {
    // constructors omitted.
}

// This declares a custom unchecked exception.
public class MyException2 extends RuntimeException {
    // constructors omitted.
}

Il primo esempio mostra come le eccezioni verificate esplicitamente generate possono essere dichiarate come "lanciate" se non devono essere gestite nel metodo.

// INCORRECT
public void methodThrowingCheckedException(boolean flag) {
    int i = 1 / 0;                // Compiles OK, throws ArithmeticException
    if (flag) {
        throw new MyException();  // Compilation error
    } else {
        throw new MyException2(); // Compiles OK
    }
}

// CORRECTED
public void methodThrowingCheckedException(boolean flag) throws MyException {
    int i = 1 / 0;                // Compiles OK, throws ArithmeticException
    if (flag) {
        throw new MyException();  // Compilation error
    } else {
        throw new MyException2(); // Compiles OK
    }
}

Il secondo esempio mostra come può essere gestita un'eccezione verificata propagata.

// INCORRECT 
public void methodWithPropagatedCheckedException() {
    InputStream is = new FileInputStream("someFile.txt");  // Compilation error
    // FileInputStream throws IOException or a subclass if the file cannot 
    // be opened.  IOException is a checked exception.
    ...
}

// CORRECTED (Version A) 
public void methodWithPropagatedCheckedException() throws IOException {
    InputStream is = new FileInputStream("someFile.txt"); 
    ...
}

// CORRECTED (Version B) 
public void methodWithPropagatedCheckedException() {
    try {
        InputStream is = new FileInputStream("someFile.txt"); 
        ...
    } catch (IOException ex) {
        System.out.println("Cannot open file: " + ex.getMessage());
    }
}

L'esempio finale mostra come gestire un'eccezione controllata in un inizializzatore di campo statico.

// INCORRECT
public class Test {
    private static final InputStream is = 
            new FileInputStream("someFile.txt");  // Compilation error
}

// CORRECTED
public class Test {
    private static final InputStream is;
    static {
        InputStream tmp = null;
        try {
            tmp = new FileInputStream("someFile.txt");
        } catch (IOException ex) {
            System.out.println("Cannot open file: " + ex.getMessage());
        }
        is = tmp;
    }
}

Si noti che in questo ultimo caso, abbiamo anche a che fare con i problemi che is non possono essere assegnati a più di una volta, ma anche deve essere assegnato a, anche nel caso di un'eccezione.