Réponses:
En général, jamais.
Cependant, vous devez parfois détecter des erreurs spécifiques.
Si vous écrivez du code framework (chargement de classes tierces), il peut être judicieux d'attraper LinkageError
(aucune définition de classe trouvée, lien insatisfait, changement de classe incompatible).
J'ai également vu du code tiers stupide lancer des sous-classes de Error
, vous devrez donc les gérer également.
Au fait, je ne suis pas sûr qu'il ne soit pas possible de récupérer OutOfMemoryError
.
Jamais. Vous ne pouvez jamais être sûr que l'application est capable d'exécuter la ligne de code suivante. Si vous obtenez un OutOfMemoryError
, vous n'avez aucune garantie de pouvoir faire quoi que ce soit de manière fiable . Attrapez RuntimeException et vérifiez les exceptions, mais jamais les erreurs.
boolean assertionsEnabled = false; assert assertionsEnabled = true;
En général, vous devriez toujours attraper java.lang.Error
et l'écrire dans un journal ou l'afficher à l'utilisateur. Je travaille en support et je constate quotidiennement que les programmeurs ne peuvent pas dire ce qui s'est passé dans un programme.
Si vous avez un thread démon, vous devez l'empêcher de se terminer. Dans d'autres cas, votre application fonctionnera correctement.
Vous ne devriez attraper java.lang.Error
qu'au plus haut niveau.
Si vous regardez la liste des erreurs, vous verrez que la plupart peuvent être traitées. Par exemple, a ZipError
se produit lors de la lecture de fichiers zip corrompus.
Les erreurs les plus courantes sont OutOfMemoryError
et NoClassDefFoundError
, qui sont les deux dans la plupart des cas des problèmes d'exécution.
Par exemple:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
peut produire un OutOfMemoryError
mais c'est un problème d'exécution et aucune raison de terminer votre programme.
NoClassDefFoundError
se produisent principalement si une bibliothèque n'est pas présente ou si vous travaillez avec une autre version de Java. S'il s'agit d'une partie facultative de votre programme, vous ne devez pas mettre fin à votre programme.
Je peux donner de nombreux autres exemples des raisons pour lesquelles il est judicieux de détecter Throwable
au plus haut niveau et de produire un message d'erreur utile.
OutOfMemoryError
n'est pas une erreur d'exécution, il n'y a aucune garantie que l'application puisse s'en remettre. Si vous avez de la chance, vous pouvez obtenir un MOO, new byte[largeNumber]
mais si cette allocation n'était pas suffisante pour provoquer un MOO, elle pourrait être déclenchée dans la ligne suivante ou dans le thread suivant. Il s'agit d'un problème d'exécution car s'il length
s'agit d'une entrée non approuvée, il doit être validé avant l'appel new byte[]
.
NoClassDefFoundError
peut se produire n'importe où , car il est appelé lorsque le code java compilé ne peut pas trouver une classe. Si votre JDK est mal configuré, il peut déclencher une tentative d'utilisation de la java.util.*
classe et il est pratiquement impossible de programmer contre lui. Si vous incluez éventuellement une dépendance, vous devez utiliser ClassLoader
pour vérifier si elle existe, ce qui déclenche ClassNotFoundException
.
ZipError
indique que le fichier jar contenant les classes est un fichier zip corrompu. C'est un problème assez sérieux et à ce stade, vous ne pouvez faire confiance à aucun code qui est exécuté et il serait irresponsable d'essayer de "récupérer".
java.lang.Error
ou java.lang.Throwable
au plus haut niveau et d'essayer de faire quelque chose avec - disons enregistrer un message d'erreur. Mais à ce stade, il n'y a aucune garantie que cela sera exécuté. Si votre JVM est en mode MOO, la tentative de journalisation peut allouer plus de String
s, ce qui déclenche un autre MOO.
Dans un environnement multithread, vous voulez le plus souvent l'attraper! Lorsque vous l'attrapez, enregistrez-le et mettez fin à toute l'application! Si vous ne le faites pas, certains threads qui pourraient faire une partie cruciale seront morts et le reste de l'application pensera que tout est normal. En dehors de cela, de nombreuses situations indésirables peuvent survenir. Le plus petit problème est que vous ne pourrez pas trouver facilement la racine du problème si d'autres threads commencent à lancer des exceptions à cause d'un thread qui ne fonctionne pas.
Par exemple, la boucle doit généralement être:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
Même dans certains cas, vous voudrez gérer différentes erreurs différemment, par exemple, sur OutOfMemoryError, vous pourrez fermer l'application régulièrement (même peut-être libérer de la mémoire et continuer), sur d'autres, vous ne pouvez pas faire grand chose.
OutOfMemoryError
et continuer plutôt que d'exister rapidement n'est pas judicieux car votre programme est alors dans un état indéfini .
Un Error
ne devrait généralement pas être attrapé , car cela indique une condition anormale qui ne devrait jamais se produire .
À partir de la spécification de l'API Java pour la Error
classe:
An
Error
est une sous-classe deThrowable
qui indique des problèmes graves qu'une application raisonnable ne devrait pas essayer d'attraper. La plupart de ces erreurs sont des conditions anormales. [...]Une méthode n'est pas obligée de déclarer dans sa clause throws des sous-classes d'erreur qui pourraient être levées pendant l'exécution de la méthode mais pas interceptées, car ces erreurs sont des conditions anormales qui ne devraient jamais se produire.
Comme l'indique la spécification, un Error
n'est lancé que dans des circonstances où il y a de fortes chances que, quand un Error
se produit, l'application ne puisse pas faire grand-chose, et dans certaines circonstances, la machine virtuelle Java elle-même peut être dans un état instable (tel que VirtualMachineError
)
Bien que an Error
soit une sous-classe de Throwable
ce qui signifie qu'elle peut être interceptée par une try-catch
clause, mais ce n'est probablement pas vraiment nécessaire, car l'application sera dans un état anormal quand une Error
est lancée par la JVM.
Il y a aussi une courte section sur ce sujet dans la Section 11.5 La hiérarchie des exceptions de la spécification du langage Java, 2e édition .
Et il y a quelques autres cas où si vous détectez une erreur, vous devez la renvoyer . Par exemple, ThreadDeath ne devrait jamais être attrapé, cela peut causer un gros problème si vous l'attrapez dans un environnement confiné (par exemple, un serveur d'applications):
Une application ne doit intercepter les instances de cette classe que si elle doit nettoyer après avoir été arrêtée de manière asynchrone. Si ThreadDeath est intercepté par une méthode, il est important qu'il soit relancé afin que le thread meurt réellement.
Error
s.
Très, très rarement.
Je ne l'ai fait que pour un cas connu très très spécifique. Par exemple, java.lang.UnsatisfiedLinkError peut être renvoyé si deux ClassLoader d'indépendance chargent la même DLL. (Je suis d'accord que je devrais déplacer le JAR vers un chargeur de classe partagé)
Mais le cas le plus courant est que vous aviez besoin d'une journalisation afin de savoir ce qui s'est passé lorsque l'utilisateur vient se plaindre. Vous voulez un message ou une fenêtre contextuelle à l'utilisateur, plutôt que silencieusement mort.
Même programmeur en C / C ++, ils affichent une erreur et disent quelque chose que les gens ne comprennent pas avant de quitter (par exemple, une panne de mémoire).
Dans une application Android, j'attrape un java.lang.VerifyError . Une bibliothèque que j'utilise ne fonctionnera pas dans les appareils avec une ancienne version du système d'exploitation et le code de la bibliothèque générera une telle erreur. Je pourrais bien sûr éviter l'erreur en vérifiant la version du système d'exploitation au moment de l'exécution, mais:
Idéalement, nous ne devrions pas gérer / détecter les erreurs. Mais il peut y avoir des cas où nous devons le faire, en fonction des exigences du cadre ou de l'application. Disons que j'ai un démon XML Parser qui implémente l' analyseur DOM qui consomme plus de mémoire. S'il y a une exigence telle que le thread Parser ne doit pas être mort lorsqu'il obtient OutOfMemoryError , il doit à la place le gérer et envoyer un message / courrier à l'administrateur de l'application / du framework.
Une erreur se produit lorsque la JVM ne fonctionne plus comme prévu ou est sur le point de le faire. Si vous détectez une erreur, il n'y a aucune garantie que le bloc catch s'exécutera, et encore moins qu'il fonctionnera jusqu'à la fin.
Cela dépendra également de l'ordinateur en cours d'exécution, de l'état actuel de la mémoire, il n'y a donc aucun moyen de tester, d'essayer et de faire de votre mieux. Vous n'aurez qu'un résultat hasardeux.
Vous réduirez également la lisibilité de votre code.