1. Tipi di eccezioni
Tutte le eccezioni sono divise in 4 tipi, che in realtà sono classi che si ereditano a vicenda.
Throwable
classe
La classe base per tutte le eccezioni è la Throwable
classe. La Throwable
classe contiene il codice che scrive lo stack di chiamate corrente (traccia dello stack del metodo corrente) in un array. Impareremo cos'è una traccia dello stack un po' più tardi.
L' operatore throw può accettare solo un oggetto che deriva dalla Throwable
classe. E sebbene tu possa teoricamente scrivere codice come throw new Throwable();
, di solito nessuno lo fa. Lo scopo principale della Throwable
classe è avere un'unica classe genitore per tutte le eccezioni.
Error
classe
La prossima classe di eccezione è la Error
classe, che eredita direttamente la Throwable
classe. La macchina Java crea oggetti della Error
classe (e dei suoi discendenti) quando si sono verificati problemi seri . Ad esempio, un malfunzionamento dell'hardware, memoria insufficiente, ecc.
Di solito, come programmatore, non c'è niente che tu possa fare in una situazione in cui si è verificato un tale errore (il tipo per il quale Error
dovrebbe essere lanciato un an): questi errori sono troppo gravi. Tutto quello che puoi fare è notificare all'utente che il programma si sta arrestando in modo anomalo e/o scrivere tutte le informazioni note sull'errore nel registro del programma.
Exception
classe
Le classi Exception
e RuntimeException
sono per errori comuni che si verificano nel funzionamento di molti metodi. L'obiettivo di ogni eccezione generata è essere catturato da un catch
blocco che sappia come gestirlo correttamente.
Quando un metodo non può completare il proprio lavoro per qualche motivo, dovrebbe immediatamente avvisare il metodo chiamante generando un'eccezione del tipo appropriato.
In altre parole, se una variabile è uguale a null
, il metodo genererà un NullPointerException
. Se gli argomenti errati sono stati passati al metodo, genererà un file InvalidArgumentException
. Se il metodo divide accidentalmente per zero, genererà un'estensione ArithmeticException
.
RuntimeException
classe
RuntimeExceptions
sono un sottoinsieme di Exceptions
. Potremmo anche dire che RuntimeException
è una versione leggera delle eccezioni ordinarie ( Exception
) — meno requisiti e restrizioni sono imposti a tali eccezioni
Imparerai la differenza tra Exception
e RuntimeException
dopo.
2. Throws
: eccezioni verificate
Tutte le eccezioni Java rientrano in 2 categorie: verificate e non verificate .
Tutte le eccezioni che ereditano RuntimeException
o Error
sono considerate eccezioni non controllate . Tutte le altre sono eccezioni controllate .
Vent'anni dopo l'introduzione delle eccezioni verificate, quasi tutti i programmatori Java lo considerano un bug. Nei framework moderni più diffusi, il 95% di tutte le eccezioni è deselezionato. Il linguaggio C#, che quasi copiava esattamente Java, non aggiungeva eccezioni controllate .
Qual è la differenza principale tra eccezioni controllate e non controllate ?
Ci sono ulteriori requisiti imposti sulle eccezioni verificate . In parole povere sono questi:
Requisito 1
Se un metodo genera un'eccezione verificata , deve indicare il tipo di eccezione nella sua firma . In questo modo, ogni metodo che lo chiama è consapevole che questa "eccezione significativa" potrebbe verificarsi in esso.
Indica le eccezioni verificate dopo i parametri del metodo dopo la throws
parola chiave (non utilizzare la throw
parola chiave per errore). Assomiglia a questo:
type method (parameters) throws exception
Esempio:
eccezione verificata | eccezione non verificata |
---|---|
|
|
Nell'esempio a destra, il nostro codice genera un'eccezione non verificata : non è richiesta alcuna azione aggiuntiva. Nell'esempio a sinistra, il metodo genera un'eccezione verificata , quindi la throws
parola chiave viene aggiunta alla firma del metodo insieme al tipo di eccezione.
Se un metodo prevede di generare più eccezioni controllate , tutte devono essere specificate dopo la throws
parola chiave, separate da virgole. L'ordine non è importante. Esempio:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
Requisito 2
Se chiami un metodo che ha verificato le eccezioni nella sua firma, non puoi ignorare il fatto che le genera.
Devi rilevare tutte queste eccezioni aggiungendo catch
blocchi per ognuna o aggiungendole a una throws
clausola per il tuo metodo.
È come se stessimo dicendo: " Queste eccezioni sono così importanti che dobbiamo rilevarle. E se non sappiamo come gestirle, allora chiunque chiami il nostro metodo deve essere avvisato che tali eccezioni possono verificarsi in esso.
Esempio:
Immagina di scrivere un metodo per creare un mondo popolato da umani. Il numero iniziale di persone viene passato come argomento. Quindi dobbiamo aggiungere eccezioni se ci sono troppo poche persone.
Creare la Terra | Nota |
---|---|
|
Il metodo genera potenzialmente due eccezioni verificate :
|
Questa chiamata al metodo può essere gestita in 3 modi:
1. Non cogliere eccezioni
Questo è più spesso fatto quando il metodo non sa come gestire correttamente la situazione.
Codice | Nota |
---|---|
|
Il metodo chiamante non rileva le eccezioni e deve informarne gli altri: le aggiunge alla propria throws clausola |
2. Cattura alcune delle eccezioni
Gestiamo gli errori che possiamo gestire. Ma quelli che non capiamo, li lanciamo al metodo di chiamata. Per fare ciò, dobbiamo aggiungere il loro nome alla clausola throws:
Codice | Nota |
---|---|
|
Il chiamante rileva solo un'eccezione verificata : LonelyWorldException . L'altra eccezione va aggiunta alla sua firma, indicandola dopo la throws parola chiave |
3. Cattura tutte le eccezioni
Se il metodo non genera eccezioni al metodo chiamante, il metodo chiamante è sempre sicuro che tutto abbia funzionato correttamente. E non sarà in grado di intraprendere alcuna azione per risolvere una situazione eccezionale.
Codice | Nota |
---|---|
|
Tutte le eccezioni vengono rilevate in questo metodo. Il chiamante sarà sicuro che tutto è andato bene. |
3. Cattura di più eccezioni
I programmatori odiano davvero duplicare il codice. Hanno persino escogitato un principio di sviluppo corrispondente: DRY : Don't Repeat Yourself. Ma quando si gestiscono le eccezioni, ci sono frequenti occasioni in cui un try
blocco è seguito da più catch
blocchi con lo stesso codice.
Oppure potrebbero esserci 3 catch
blocchi con lo stesso codice e altri 2 catch
blocchi con altro codice identico. Questa è una situazione standard in cui il tuo progetto gestisce le eccezioni in modo responsabile.
A partire dalla versione 7, nel linguaggio Java è stata aggiunta la possibilità di specificare più tipi di eccezioni in un singolo catch
blocco. Sembra più o meno così:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
Puoi avere tutti catch
i blocchi che vuoi. Tuttavia, un singolo catch
blocco non può specificare eccezioni che si ereditano a vicenda. In altre parole, non puoi scrivere catch ( Exception
| RuntimeException
e), perché la RuntimeException
classe eredita Exception
.
GO TO FULL VERSION