Question

Est-ce une mauvaise pratique d'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 ?

Était-ce utile?

La solution

Vous devez être aussi précis que possible.Sinon, des bugs imprévus pourraient disparaître de cette façon.

En plus, Throwable couvre Error aussi et c'est généralement pas de 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.

Autres conseils

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() bloque pendant un certain temps et qu'un autre thread arrête votre thread de la pire des manières (il appelle thread.stop() ).Votre bloc catch attrapera un 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 getUserInput() a é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 que vous 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 final pour ne pas avoir à penser à relancer :

 Resources r = null;
 try {
      r = allocateSomeResources();
      doSomething(r);
 } finally {
     if(r!=null) cleanUpResources(r);
 }

Sachez également que lorsque vous attrapez Throwable, vous pouvez aussi attraper InterruptedException ce qui nécessite un traitement particulier.Voir Gérer l'exception interrompue pour plus de détails.

Si vous souhaitez uniquement détecter les exceptions non vérifié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 pouvant lever une exception vérifiée, le compilateur vous le rappellera et vous pourrez alors décider quoi faire dans ce cas.

directement depuis le 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 faire sortir une bulle d'exception d'une méthode.

C'est une mauvaise pratique si vous ne pouvez vraiment pas gérer l'exception.Mieux vaut ajouter des "lancements" à la signature de la méthode plutôt que de simplement attraper et relancer ou, pire encore, l'envelopper dans une RuntimeException et relancer.

Catching Throwable est parfois nécessaire si vous utilisez des bibliothèques qui génèrent des erreurs avec trop d'enthousiasme, sinon votre bibliothèque risque de tuer votre application.

Cependant, il serait préférable dans ces circonstances de spécifier uniquement 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 pouvant être lancées (pas seulement les exceptions).Vous ne pouvez pas faire grand-chose si vous détectez une erreur OutOfMemoryError ou KernelError (voir Quand attraper java.lang.Error ?)

attraper les exceptions devrait suffire.

cela dépend de votre logique ou pour être plus précis de vos options/possibilités.S'il existe une exception spécifique à 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 de faire la même chose pour toutes les exceptions et erreurs (par exemple, quitter avec un message d'erreur), ce n'est pas un problème d'attraper le lanceur.

Habituellement, le premier cas est valable et vous n'attraperez pas le jetable.Mais il existe encore de nombreux cas où la détection fonctionne correctement.

Bien que cela soit décrit comme une très mauvaise pratique, vous pouvez parfois constater rare cas où cela est non seulement utile mais aussi obligatoire.Voici deux exemples.

Dans une application Web où vous devez afficher une page d’erreur complète et significative à l’utilisateur.Ce code garantit 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 disposez d’une classe de service qui sert aux activités de transfert de fonds.Cette méthode renvoie un TransferReceipt si le transfert est effectué ou NULL si ce n'était pas possible.

String FoundtransferService.doTransfer( fundtransferVO);

Imaginez maintenant que vous obtenez un List des transferts de fonds de l'utilisateur et vous devez utiliser le service ci-dessus pour tous les effectuer.

for(FundTransferVO fundTransferVO : fundTransferVOList){
   FoundtransferService.doTransfer( foundtransferVO);
}

Mais que se passera-t-il si n'importe lequel 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 affichez le résultat à chaque transfert.Vous vous retrouvez donc 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 de 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

La question est un peu vague ;demandez-vous "est-ce que c'est OK d'attraper Throwable", ou " est-il acceptable d'attraper un Throwable et ne rien faire" ?Beaucoup de gens ici ont répondu à cette dernière question, mais c'est une question secondaire ;99 % du temps, vous ne devriez pas « consommer » ou rejeter l'exception, que vous soyez en train d'attraper Throwable ou IOException ou peu importe.

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 avec l'exception et de la raison pour laquelle vous l'attrapez.

Un bon exemple de la raison pour laquelle vous voudriez attraper Throwable est de fournir une sorte de nettoyage en cas d'erreur.Par exemple dans JDBC, si une erreur se produit lors d'une transaction, vous souhaiterez annuler la transaction :

try {
  …
} catch(final Throwable throwable) {
  connection.rollback();
  throw throwable;
}

Notez que l'exception n'est pas ignorée, mais propagée.

Mais en règle générale, attraper Throwable parce que vous n'avez pas de raison et que vous êtes trop paresseux pour voir quelles exceptions spécifiques sont levées, c'est une mauvaise forme et une mauvaise idée.

D'une manière générale, vous voulez éviter d'attraper Errors mais je peux penser à (au moins) deux cas spécifiques où il est approprié de le faire :

  • Vous souhaitez arrêter l'application en réponse à des erreurs, notamment AssertionError ce qui est par ailleurs inoffensif.
  • Implémentez-vous un mécanisme de pooling de threads similaire à ExecutorService.submit() cela vous oblige à renvoyer les exceptions à l'utilisateur afin qu'il puisse les gérer.

Si nous utilisons jetable, alors il couvre Erreur aussi 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();
}

}

Sortir:

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 exceptions.Si vous utilisez Throwable dans une clause catch, il interceptera non seulement toutes les exceptions, mais également toutes les erreurs.Des erreurs sont générées par la JVM pour indiquer des problèmes graves qui ne sont pas destinés à être traités par une application.Des exemples typiques sont OutOfMemoryError ou StackOverflowError.Les deux sont causés par des situations qui échappent au contrôle de l’application et ne peuvent pas être gérées.Vous ne devriez donc pas attraper Throwables à moins que vous soyez sûr que ce ne sera qu'une exception résidant à l'intérieur de Throwable.

Bien qu'il soit généralement une mauvaise pratique d'attraper Throwable (comme l'expliquent les nombreuses réponses à cette question), les scénarios où attraper Throwable est utile sont assez courants.Permettez-moi d'expliquer un de ces cas que j'utilise dans mon travail, avec un exemple simplifié.

Considérons une méthode qui effectue l'addition de deux nombres et, une fois l'ajout réussi, envoie une alerte par e-mail à certaines personnes.Supposons que le numéro renvoyé soit 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 permettant d'envoyer des alertes par courrier électronique lit de nombreuses configurations système et, par conséquent, diverses exceptions peuvent être générées à partir de ce bloc de code.Mais nous ne voulons pas qu'une exception rencontrée lors de l'envoi d'une alerte se propage à la méthode appelante, car cette méthode concerne simplement la somme des deux valeurs entières qu'elle fournit.Ainsi, le code pour envoyer les alertes email est placé dans un try-catch bloquer, où Throwable est intercepté et toutes les exceptions sont simplement enregistrées, permettant au reste du flux de continuer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top