Quand attraper java.lang.Error?

Réponses:

101

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.

Yoni Roit
la source
3
Ce que je devais faire exactement pour charger les DLL, cela échouerait si elles n'étaient pas correctement configurées. Pas une erreur fatale dans le cas de cette application.
Mario Ortegón
7
Il est parfois judicieux d'attraper OutOfMemoryError - par exemple lorsque vous créez de grandes listes de tableaux.
SpaceTrucker
3
@SpaceTrucker: cette approche fonctionne-t-elle bien dans les applications multithread, ou y a-t-il un risque important que des allocations plus petites dans d'autres threads échouent à cause de cela? … Vraisemblablement seulement si vos tableaux étaient juste assez petits pour être alloués, mais ne laissaient rien pour personne d'autre.
PJTraill
@PJTraill Je n'en suis pas sûr. Cela nécessiterait des échantillons statistiques du monde réel. Je pensais avoir vu un tel code, mais je ne me souviens pas où il se trouvait.
SpaceTrucker
51

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.

http://pmd.sourceforge.net/rules/strictexception.html

tronda
la source
27
Ne jamais dire jamais. nous avons un code de test qui fait un "assert false"; attrape ensuite AssertionError pour s'assurer que l'indicateur -ea est défini. A part ça ... ouais, probablement jamais ;-)
Outlaw Programmer
3
Que diriez-vous d'une application serveur qui transmet les demandes aux threads de travail. Ne serait-il pas logique d'attraper Throwable sur le thread de travail pour piéger les erreurs, et au moins essayer de consigner ce qui ne va pas?
Leigh
11
Jamais ... sauf lorsque vous en avez absolument besoin. Jamais un mot fort et il y a toujours des exceptions aux règles. Si vous créez un framework, il n'est pas si improbable que vous deviez attraper et gérer certaines erreurs, même si ce n'est que pour vous connecter.
Robin
Qu'en est-il des erreurs, par exemple NoSuchMethodError qui provient de méthodes de bibliothèque tierces?
ha9u63ar
@OutlawProgrammer Pour mémoire, il existe d'autres moyens de faire le même test:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel
16

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.Errorqu'au plus haut niveau.

Si vous regardez la liste des erreurs, vous verrez que la plupart peuvent être traitées. Par exemple, a ZipErrorse produit lors de la lecture de fichiers zip corrompus.

Les erreurs les plus courantes sont OutOfMemoryErroret 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 OutOfMemoryErrormais c'est un problème d'exécution et aucune raison de terminer votre programme.

NoClassDefFoundErrorse 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 Throwableau plus haut niveau et de produire un message d'erreur utile.

Horcruxe7
la source
Je soupçonne qu'il vaut mieux dans ces cas échouer le démon avec des alertes appropriées, puis avoir la possibilité qu'il reste en vie en tant que fantôme éthérique sur un jvm échoué où il pourrait donner le faux prétexte qu'il est vraiment vivant et fait quelque chose
Andrew Norman
OutOfMemoryErrorn'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 lengths'agit d'une entrée non approuvée, il doit être validé avant l'appel new byte[].
Jeeyoung Kim
NoClassDefFoundErrorpeut 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 ClassLoaderpour vérifier si elle existe, ce qui déclenche ClassNotFoundException.
Jeeyoung Kim
1
ZipErrorindique 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".
Jeeyoung Kim
2
En général, il peut être utile d'attraper java.lang.Errorou java.lang.Throwableau 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 Strings, ce qui déclenche un autre MOO.
Jeeyoung Kim
15

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.

Sarmun
la source
1
Attraper OutOfMemoryError et continuer plutôt que d'exister rapidement n'est pas judicieux car votre programme est alors dans un état indéfini .
Raedwald
1
appelant le système, quitter lors de la capture d'un jetable a pour conséquence inattendue de tuer tout ce qui tourne sur la JVM et pas seulement l'application en question. Ce n'est généralement pas une bonne pratique pour les applications Web qui pourraient être hébergées sur un serveur d'applications avec d'autres applications Web (sans oublier que cela aurait un impact sur le serveur d'applications lui-même).
Andrew Norman le
9

Très rarement.

Je dirais seulement au niveau supérieur d'un fil afin d'essayer d'émettre un message avec la raison de la mort d'un fil.

Si vous êtes dans un cadre qui fait ce genre de chose pour vous, laissez-le au cadre.

Darron
la source
6

Presque jamais. Les erreurs sont conçues pour être des problèmes auxquels les applications ne peuvent généralement rien faire. La seule exception peut être de gérer la présentation de l'erreur, mais même cela peut ne pas se dérouler comme prévu en fonction de l'erreur.

Nicerobot
la source
6

Un Errorne 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 Errorclasse:

An Errorest une sous-classe de Throwable 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 Errorn'est lancé que dans des circonstances où il y a de fortes chances que, quand un Errorse 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 Errorsoit une sous-classe de Throwablece qui signifie qu'elle peut être interceptée par une try-catchclause, mais ce n'est probablement pas vraiment nécessaire, car l'application sera dans un état anormal quand une Errorest 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 .

coobird
la source
6

Si vous êtes assez fou pour créer un nouveau framework de test unitaire, votre lanceur de test devra probablement attraper java.lang.AssertionError généré par tous les cas de test.

Sinon, voyez d'autres réponses.

Noahlz
la source
5

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.

Guillaume
la source
2
Ce qui est en fait pas un problème parce que vous n'avez tout simplement pas prises Errors.
Bombe
4

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).

Dennis C
la source
3

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:

  • Le plus ancien SDK pris en charge peut changer à l'avenir pour la bibliothèque spécifique
  • Le bloc d'erreur try-catch fait partie d'un mécanisme de repli plus important. Certains périphériques spécifiques, bien qu'ils soient censés prendre en charge la bibliothèque, lancent des exceptions. J'attrape VerifyError et toutes les exceptions pour utiliser une solution de secours.
kgiannakakis
la source
3

c'est assez pratique d'attraper java.lang.AssertionError dans un environnement de test ...

Jono
la source
Quelle valeur essayez-vous d'ajouter?
lpapp
ajout de la valeur d'une suite de tests ne pas abandonner
Jono
2

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.

user3510364
la source
1

idéalement, nous ne devrions jamais détecter d'erreur dans notre application Java car il s'agit d'une condition anormale. L'application serait dans un état anormal et pourrait entraîner un basculement ou donner un résultat gravement faux.

Vivek
la source
1

Il peut être approprié de détecter une erreur dans les tests unitaires qui vérifient qu'une assertion est faite. Si quelqu'un désactive les assertions ou supprime d'une autre manière l'assertion que vous voudriez savoir

Chanoch
la source
1

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.

Nicolas Zozol
la source