Est-ce une mauvaise pratique à attraper Throwable
?
Par exemple quelque chose comme ceci:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
Est-ce une mauvaise pratique ou devrions-nous être aussi précis que possible?
Est-ce une mauvaise pratique à attraper Throwable
?
Par exemple quelque chose comme ceci:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
Est-ce une mauvaise pratique ou devrions-nous être aussi précis que possible?
Réponses:
Vous devez être aussi précis que possible. Sinon, des bugs imprévus pourraient s'éloigner de cette façon.
En outre, les Throwable
couvertures Error
aussi et ce n'est généralement pas un point de retour . Vous ne voulez pas attraper / gérer cela, vous voulez que votre programme meure immédiatement afin que vous puissiez le réparer correctement.
C'est une mauvaise idée. En fait, même attraper Exception
est généralement une mauvaise idée. Prenons un exemple:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
inputNumber = 10; //Default, user did not enter valid number
}
Maintenant, disons que getUserInput () se bloque pendant un certain temps et qu'un autre thread arrête votre thread de la pire manière possible (il appelle thread.stop ()). Votre bloc catch attrapera une ThreadDeath
erreur. C'est super mauvais. Le comportement de votre code après avoir détecté cette exception est en grande partie indéfini.
Un problème similaire se produit lors de la capture d'Exception. Peut-être a getUserInput()
échoué en raison d'une InterruptException, ou d'une exception d'autorisation refusée lors de la tentative de journalisation des résultats, ou de toutes sortes d'autres échecs. Vous n'avez aucune idée de ce qui n'a pas fonctionné, car à cause de cela, vous ne savez pas non plus comment résoudre le problème.
Vous avez trois meilleures options:
1 - Attrapez exactement la ou les exceptions que vous savez gérer:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
inputNumber = 10; //Default, user did not enter valid number
}
2 - Relancez toute exception que vous rencontrez et ne savez pas comment gérer:
try {
doSomethingMysterious();
} catch(Exception e) {
log.error("Oh man, something bad and mysterious happened",e);
throw e;
}
3 - Utilisez un bloc finally pour ne pas avoir à vous rappeler de relancer:
Resources r = null;
try {
r = allocateSomeResources();
doSomething(r);
} finally {
if(r!=null) cleanUpResources(r);
}
throw new Exception("Some additional info, eg. userId " + userId, e);
. Cela sera enregistré dans une belle exception avec 10 causes.
Sachez également que lorsque vous attrapez Throwable
, vous pouvez également attraper InterruptedException
ce qui nécessite un traitement spécial. Pour plus de détails, consultez Traitement de l'exception InterruptedException .
Si vous souhaitez uniquement intercepter les exceptions non contrôlées, vous pouvez également envisager ce modèle
try {
...
} catch (RuntimeException exception) {
//do something
} catch (Error error) {
//do something
}
De cette façon, lorsque vous modifiez votre code et ajoutez un appel de méthode qui peut lever une exception vérifiée, le compilateur vous le rappellera et vous pourrez ensuite décider quoi faire dans ce cas.
directement à partir du javadoc de la classe Error (qui recommande de ne pas les attraper):
* An <code>Error</code> is a subclass of <code>Throwable</code>
* that indicates serious problems that a reasonable application
* should not try to catch. Most such errors are abnormal conditions.
* The <code>ThreadDeath</code> error, though a "normal" condition,
* is also a subclass of <code>Error</code> because most applications
* should not try to catch it.
* A method is not required to declare in its <code>throws</code>
* clause any subclasses of <code>Error</code> that might be thrown
* during the execution of the method but not caught, since these
* errors are abnormal conditions that should never occur.
*
* @author Frank Yellin
* @version %I%, %G%
* @see java.lang.ThreadDeath
* @since JDK1.0
Ce n'est pas une mauvaise pratique si vous ne pouvez absolument pas avoir une bulle d'exception hors d'une méthode.
C'est une mauvaise pratique si vous ne pouvez vraiment pas gérer l'exception. Mieux vaut ajouter des "jets" à la signature de la méthode que simplement attraper et relancer ou, pire, l'envelopper dans une RuntimeException et la relancer.
Throwable
instances - par exemple pour la journalisation des exceptions personnalisée.
Catching Throwable est parfois nécessaire si vous utilisez des bibliothèques qui lancent des erreurs avec trop d'enthousiasme, sinon votre bibliothèque peut tuer votre application.
Cependant, il serait préférable dans ces circonstances de ne spécifier que les erreurs spécifiques générées par la bibliothèque, plutôt que tous les Throwables.
Throwable est la classe de base pour toutes les classes qui peuvent être levées (pas seulement les exceptions). Vous ne pouvez pas faire grand-chose si vous attrapez une OutOfMemoryError ou KernelError (voir Quand attraper java.lang.Error? )
attraper des exceptions devrait suffire.
cela dépend de votre logique ou pour être plus spécifique à vos options / possibilités. S'il y a une exception spécifique sur laquelle vous pouvez éventuellement réagir de manière significative, vous pouvez la détecter en premier et le faire.
S'il n'y en a pas et que vous êtes sûr que vous ferez la même chose pour toutes les exceptions et erreurs (par exemple, quitter avec un message d'erreur), alors ce n'est pas un problème pour attraper le jetable.
Habituellement, le premier cas tient et vous n'attraperez pas le jetable. Mais il existe encore de nombreux cas où l'attraper fonctionne bien.
Bien que cela soit décrit comme une très mauvaise pratique, vous pouvez parfois trouver de rares cas où cela est non seulement utile mais également obligatoire. Voici deux exemples.
Dans une application Web où vous devez montrer une page d'erreur complète à l'utilisateur. Ce code s'assure que cela se produit car il s'agit d'un gros try/catch
autour de tous vos gestionnaires de requêtes (servlets, actions struts ou tout contrôleur ....)
try{
//run the code which handles user request.
}catch(Throwable ex){
LOG.error("Exception was thrown: {}", ex);
//redirect request to a error page.
}
}
Comme autre exemple, considérons que vous avez une classe de service qui sert les activités de transfert de fonds. Cette méthode renvoie un TransferReceipt
si le transfert est effectué ou NULL
s'il n'a pas pu.
String FoundtransferService.doTransfer( fundtransferVO);
Maintenant, vous obtenez une image List
des transferts de fonds de l'utilisateur et vous devez utiliser le service ci-dessus pour les faire tous.
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}
Mais que se passera-t-il si une exception se produit? Vous ne devez pas vous arrêter, car un transfert peut avoir été un succès et un autre non, vous devez continuer à travers tous les utilisateurs List
et afficher le résultat à chaque transfert. Donc, vous vous retrouvez avec ce code.
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}catch(Throwable ex){
LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
}
}
Vous pouvez parcourir de nombreux projets open source pour voir que le throwable
est vraiment mis en cache et géré. Par exemple, voici une recherche sur tomcat
, struts2
et primefaces
:
https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch % 28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable
throwable
, c'est sur quoi porte cette question
La question est un peu vague; demandez-vous "est-il OK pour attraper Throwable
", ou "est-il OK pour attraper Throwable
et ne rien faire"? Beaucoup de gens ici ont répondu à cette dernière question, mais c'est un problème secondaire; 99% du temps , vous ne devriez pas « consommer » ou rejeter l'exception, si vous attrapez Throwable
ou IOException
ou autre.
Si vous propagez l'exception, la réponse (comme la réponse à tant de questions) est "ça dépend". Cela dépend de ce que vous faites à l'exception de la raison pour laquelle vous l'attrapez.
Un bon exemple des raisons pour lesquelles vous voudriez attraper Throwable
est de fournir une sorte de nettoyage en cas d'erreur. Par exemple dans JDBC, si une erreur se produit pendant une transaction, vous voudrez annuler la transaction:
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
Notez que l'exception n'est pas rejetée, mais propagée.
Mais en Throwable
règle générale, attraper parce que vous n'avez pas de raison et que vous êtes trop paresseux pour voir quelles exceptions spécifiques sont lancées est une mauvaise forme et une mauvaise idée.
De manière générale, vous voulez éviter d'attraper des Error
s mais je peux penser à (au moins) deux cas spécifiques où il convient de le faire:
AssertionError
ce qui est par ailleurs inoffensif.Si nous utilisons throwable , cela couvre également Error et c'est tout.
Exemple.
public class ExceptionTest {
/**
* @param args
*/
public static void m1() {
int i = 10;
int j = 0;
try {
int k = i / j;
System.out.println(k);
} catch (Throwable th) {
th.printStackTrace();
}
}
public static void main(String[] args) {
m1();
}
}
Production:
java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.java:25)
Throwable est la superclasse de toutes les erreurs et excétions. Si vous utilisez Throwable dans une clause catch, il détectera non seulement toutes les exceptions, mais également toutes les erreurs. Des erreurs sont émises par la JVM pour indiquer des problèmes graves qui ne sont pas destinés à être traités par une application. Des exemples typiques pour cela sont OutOfMemoryError ou StackOverflowError. Les deux sont causés par des situations qui sont hors du contrôle de l'application et ne peuvent pas être gérées. Donc, vous ne devriez pas attraper Throwables à moins que vous ne soyez convaincu que ce ne sera qu'une exception résidant dans Throwable.
Bien qu'il soit généralement une mauvaise pratique d'attraper Throwable (comme le montrent les nombreuses réponses à cette question), les scénarios où la capture Throwable
est utile sont assez courants. Permettez-moi de vous expliquer un cas que j'utilise dans mon travail, avec un exemple simplifié.
Considérez une méthode qui effectue l'ajout de deux nombres, et après l'ajout réussi, elle envoie une alerte par e-mail à certaines personnes. Supposons que le nombre retourné est important et utilisé par la méthode appelante.
public Integer addNumbers(Integer a, Integer b) {
Integer c = a + b; //This will throw a NullPointerException if either
//a or b are set to a null value by the
//calling method
successfulAdditionAlert(c);
return c;
}
private void successfulAdditionAlert(Integer c) {
try {
//Code here to read configurations and send email alerts.
} catch (Throwable e) {
//Code to log any exception that occurs during email dispatch
}
}
Le code pour envoyer des alertes par e-mail lit un grand nombre de configurations système et, par conséquent, il peut y avoir une variété d'exceptions lancées à partir de ce bloc de code. Mais nous ne voulons pas qu'une exception rencontrée lors de l'envoi d'alertes se propage à la méthode de l'appelant, car cette méthode est simplement concernée par la somme des deux valeurs Integer qu'elle fournit. Par conséquent, le code pour envoyer les alertes par e-mail est placé dans un try-catch
bloc, où Throwable
est intercepté et toutes les exceptions sont simplement enregistrées, ce qui permet au reste du flux de continuer.
Exception
s par tous les moyens, mais pas Throwable
.