Risposte:
In genere, mai.
Tuttavia, a volte è necessario rilevare errori specifici.
Se stai scrivendo codice framework-ish (caricando classi di terze parti), potrebbe essere saggio prendere LinkageError
(nessuna definizione di classe trovata, collegamento insoddisfatto, cambio di classe incompatibile).
Ho anche visto alcuni stupidi codici di terze parti che lanciano sottoclassi Error
, quindi dovrai gestire anche quelli.
A proposito, non sono sicuro che non sia possibile riprendersi OutOfMemoryError
.
Mai. Non si può mai essere sicuri che l'applicazione sia in grado di eseguire la riga di codice successiva. Se ottieni un messaggio OutOfMemoryError
, non hai alcuna garanzia che sarai in grado di fare qualcosa in modo affidabile . Cattura RuntimeException e controllato le eccezioni, ma mai gli errori.
boolean assertionsEnabled = false; assert assertionsEnabled = true;
Generalmente dovresti sempre prenderlo java.lang.Error
e scriverlo in un registro o mostrarlo all'utente. Lavoro in supporto e vedo ogni giorno che i programmatori non possono dire cosa è successo in un programma.
Se si dispone di un thread daemon, è necessario impedire che venga terminato. In altri casi la tua applicazione funzionerà correttamente.
Dovresti catturare solo java.lang.Error
al livello più alto.
Se guardi l'elenco degli errori vedrai che la maggior parte può essere gestita. Ad esempio aZipError
verifica quando si leggono file zip corrotti.
Gli errori più comuni sono OutOfMemoryError
eNoClassDefFoundError
, che sono entrambi nella maggior parte dei casi problemi di runtime.
Per esempio:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
può produrre un file OutOfMemoryError
ma è un problema di runtime e non c'è motivo per terminare il programma.
NoClassDefFoundError
si verificano principalmente se una libreria non è presente o se si lavora con un'altra versione di Java. Se è una parte facoltativa del programma, non interrompere il programma.
Posso fornire molti altri esempi del motivo per cui è una buona idea catturare Throwable
il livello più alto e produrre un utile messaggio di errore.
OutOfMemoryError
non è un errore di runtime non esiste alcuna garanzia che l'applicazione possa ripristinarlo. Se sei fortunato, potresti ottenere OOM, new byte[largeNumber]
ma se tale allocazione non fosse sufficiente per causare OOM, potrebbe essere attivato nella riga successiva o nel thread successivo. Questo è un problema di runtime perché se length
è un input non attendibile dovrebbe essere convalidato prima di chiamare new byte[]
.
NoClassDefFoundError
può verificarsi ovunque , poiché viene invocato quando il codice java compilato non riesce a trovare una classe. Se il tuo JDK è configurato in modo errato, può innescarsi dal tentativo di utilizzare la java.util.*
classe ed è praticamente impossibile programmarlo. Se opzionalmente includi una dipendenza, dovresti usarla ClassLoader
per verificare se esiste, che genera ClassNotFoundException
.
ZipError
indica che il file jar contenente le classi è un file zip danneggiato. Questo è un problema abbastanza serio ea questo punto non puoi fidarti di alcun codice che viene eseguito e sarebbe una cosa irresponsabile tentare di "recuperare" da esso.
java.lang.Error
o java.lang.Throwable
al massimo livello e tentare di fare qualcosa con esso, ad esempio registrare un messaggio di errore. Ma a quel punto non vi è alcuna garanzia che ciò venga eseguito. Se la tua JVM è OOM, il tentativo di log potrebbe allocare più messaggi di posta elettronica String
che innesca un altro OOM.
Nell'ambiente multithread, la maggior parte delle volte si desidera catturarlo! Quando lo prendi, registralo e chiudi l'intera applicazione! Se non lo fai, qualche thread che potrebbe svolgere una parte cruciale sarebbe morto e il resto dell'applicazione penserà che tutto sia normale. Oltre a ciò, possono verificarsi molte situazioni indesiderate. Un problema più piccolo è che non saresti in grado di trovare facilmente la radice del problema, se altri thread iniziassero a lanciare alcune eccezioni a causa di un thread non funzionante.
Ad esempio, di solito il ciclo dovrebbe essere:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
Anche in alcuni casi, vorresti gestire diversi Errori in modo diverso, ad esempio, su OutOfMemoryError potresti chiudere l'applicazione regolarmente (magari anche liberare un po 'di memoria e continuare), su altri, non c'è molto che puoi fare.
OutOfMemoryError
e continuare piuttosto che esistere prontamente non è saggio perché il tuo programma è quindi in uno stato indefinito .
Di Error
solito non dovrebbe essere catturato , poiché indica una condizione anormale che non dovrebbe mai verificarsi .
Dalla specifica dell'API Java per la Error
classe:
An
Error
è una sottoclasse diThrowable
che indica problemi seri che un'applicazione ragionevole non dovrebbe cercare di individuare. La maggior parte di questi errori sono condizioni anormali. [...]Un metodo non è tenuto a dichiarare nella sua clausola throws eventuali sottoclassi di Error che potrebbero essere lanciate durante l'esecuzione del metodo ma non catturate, poiché questi errori sono condizioni anormali che non dovrebbero mai verificarsi.
Come menzionato nella specifica, un Error
viene lanciato solo in circostanze che sono Probabili, quando si Error
verifica, l'applicazione può fare molto poco e in alcune circostanze, la Java Virtual Machine stessa potrebbe trovarsi in uno stato instabile (come VirtualMachineError
)
Sebbene an Error
sia una sottoclasse, Throwable
ciò significa che può essere catturato da una try-catch
clausola, ma probabilmente non è realmente necessario, poiché l'applicazione si troverà in uno stato anormale quando un Error
viene lanciato dalla JVM.
C'è anche una breve sezione su questo argomento nella Sezione 11.5 The Exception Hierarchy of the Java Language Specification, 2nd Edition .
E ci sono un paio di altri casi in cui se rilevi un errore, devi rilanciarlo . Ad esempio ThreadDeath non dovrebbe mai essere catturato, può causare un grosso problema se lo prendi in un ambiente contenuto (ad es. Un application server):
Un'applicazione dovrebbe catturare istanze di questa classe solo se deve essere ripulita dopo essere stata terminata in modo asincrono. Se ThreadDeath viene rilevato da un metodo, è importante che venga rilanciato in modo che il thread muoia effettivamente.
Error
s.
Molto, molto raramente.
L'ho fatto solo per un caso noto molto molto specifico. Ad esempio, java.lang.UnsatisfiedLinkError potrebbe essere lanciato se due ClassLoader di indipendenza caricano la stessa DLL. (Sono d'accordo che dovrei spostare il JAR su un classloader condiviso)
Ma il caso più comune è che hai bisogno di loggarti per sapere cosa è successo quando l'utente si è presentato a lamentarsi. Vuoi un messaggio o un popup per l'utente, piuttosto che silenziosamente morto.
Anche i programmatori in C / C ++, fanno apparire un errore e dicono qualcosa che la gente non capisce prima che esca (es. Errore di memoria).
In un'applicazione Android sto catturando java.lang.VerifyError . Una libreria che sto utilizzando non funzionerà su dispositivi con una vecchia versione del sistema operativo e il codice della libreria genererà un tale errore. Ovviamente potrei evitare l'errore controllando la versione del sistema operativo in fase di esecuzione, ma:
Idealmente non dovremmo gestire / rilevare errori. Ma ci possono essere casi in cui dobbiamo farlo, in base ai requisiti del framework o dell'applicazione. Supponiamo che io abbia un demone XML Parser che implementa DOM Parser che consuma più memoria. Se c'è un requisito come il thread Parser non dovrebbe essere morto quando ottiene OutOfMemoryError , invece dovrebbe gestirlo e inviare un messaggio / posta all'amministratore dell'applicazione / framework.
Si verifica un errore quando la JVM non funziona più come previsto o è in procinto di farlo. Se si rileva un errore, non vi è alcuna garanzia che il blocco catch verrà eseguito e ancor meno che verrà eseguito fino alla fine.
Dipenderà anche dal computer in esecuzione, dallo stato della memoria corrente, quindi non c'è modo di testare, provare e fare del tuo meglio. Avrai solo un risultato fastidioso.
Eseguirai anche il downgrade della leggibilità del codice.