web-dev-qa-db-fra.com

Est-ce une mauvaise pratique d'attraper Throwable?

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?

94
ktulinho

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

En outre, Throwable couvre Error aussi bien et c'est généralement pas de point de retour . Vous ne voulez pas attraper/gérer cela, vous voulez que votre programme meurt immédiatement pour pouvoir le réparer correctement.

88
BalusC

C'est une mauvaise idée. En fait, même attraper Exception est généralement une mauvaise idée. Considérons un exemple:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
    inputNumber = 10; //Default, user did not enter valid number
}

Supposons maintenant que getUserInput () bloque pendant un certain temps et qu'un autre thread arrête votre thread de la pire façon possible (il appelle thread.stop ()). Votre bloc catch capturera une erreur ThreadDeath. C'est super mauvais. Le comportement de votre code après avoir intercepté cette exception est en grande partie indéfini.

Un problème similaire se produit avec catching Exception. Peut-être que getUserInput() a échoué à cause d'une exception InterruptException ou d'une autorisation refusée lors de la tentative de journalisation des résultats, ou de toutes sortes d'autres échecs. Vous ne savez pas ce qui ne va pas, car à cause de cela, vous ne savez pas non plus comment résoudre le problème.

Vous avez trois meilleures options:

1 - Catch exactement la ou les exception (s) que vous savez manipuler:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
    inputNumber = 10; //Default, user did not enter valid number
}

2 - Renouvelez 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 finally pour ne pas avoir à vous rappeler de réémettre:

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

Sachez également que lorsque vous attrapez Throwable, vous pouvez également attraper InterruptedException qui nécessite un traitement spécial. Voir Traiter avec InterruptedException pour plus de détails.

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 pouvant générer une exception vérifiée, le compilateur vous le rappelle et vous permet de décider quoi faire dans ce cas.

19
gawi

Ce n'est pas une mauvaise pratique si vous ne pouvez absolument pas créer une bulle d'exception dans une méthode.

C'est une mauvaise pratique si vous ne pouvez vraiment pas gérer l'exception. Il est préférable d’ajouter des "jets" à la signature de la méthode que de simplement attraper et relancer ou, pire, de l’envelopper dans une exception RuntimeException et de relancer.

13
duffymo

directement depuis le javadoc de la classe Error (qui recommande de ne pas attraper ceux-ci):

 * 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
13
Andrew Norman

Catching Throwable est parfois nécessaire si vous utilisez des bibliothèques qui génèrent des erreurs de manière trop enthousiaste. Dans le cas contraire, votre bibliothèque pourrait 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.

9
DNA

Throwable est la classe de base pour toutes les classes pouvant être levées (pas seulement les exceptions). Il y a peu de choses que vous puissiez faire si vous attrapez une erreur OutOfMemoryError ou KernelError (voir Quand attraper Java.lang.Error? )

attraper des exceptions devrait être suffisant.

5
ic3

cela dépend de votre logique ou d'être plus spécifique à vos options/possibilités. S'il existe une exception spécifique pour 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 les erreurs (par exemple, quitter avec un message d'erreur), il n'y a aucun problème pour attraper le jetable.

Habituellement, le premier cas est valable et vous ne pourriez pas attraper le jetable. Mais il y a encore beaucoup de cas où la capture fonctionne bien.

5
b.buchhold

Bien que cela soit décrit comme une très mauvaise pratique, vous pouvez parfois trouver des cas rares qu’il soit non seulement utile, mais également obligatoire. Voici deux exemples.

Dans une application Web où vous devez afficher une page d'erreur de sens complet à l'utilisateur. Ce code s'assure que cela se produit car c'est 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 services qui sert aux entreprises de transfert de fonds. Cette méthode retourne un TransferReceipt si le transfert est effectué ou NULL s'il ne le peut pas.

String FoundtransferService.doTransfer( fundtransferVO);

Imaginez maintenant que vous obtenez un List de virements de fonds d'un utilisateur et que vous devez utiliser le service ci-dessus pour tout faire.

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 ne le peut pas. Vous devez continuer à consulter 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 réellement 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% 28Throwablehttps: //github.com/Apache/struts/search? utf8 =% E2% 9C% 93 & q = catch% 28Throwablehttps: //github.com/primefaces/primefaces/search? utf8 =% E2% 9C% 93 & q = catch% 28Ajouté

5
Alireza Fattahi

La question est un peu vague. demandez-vous "est-il correct d'attraper Throwable" ou "est-il correct d'attraper un Throwable et de ne rien faire"? Beaucoup de personnes ici ont répondu à cette dernière question, mais c'est une question secondaire; 99% du temps, vous ne devriez pas "consommer" ou supprimer l'exception, que vous preniez Throwable ou IOException ou autre chose.

Si vous propagez l'exception, la réponse (comme celle de tant de questions) est "ça dépend". Cela dépend de ce que vous faites avec l'exception - pourquoi vous l'attrapez.

Un bon exemple de la raison pour laquelle vous souhaitez intercepter Throwable consiste à effectuer un nettoyage en cas d'erreur. Par exemple, dans JDBC, si une erreur se produit pendant une transaction, vous souhaitez 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 êtes trop paresseux pour voir quelles exceptions spécifiques sont levées est une mauvaise forme et une mauvaise idée.

4
Garret Wilson

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

}

Sortie:

Java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.Java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.Java:25)
0
VicXj

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

Envisagez une méthode qui consiste à ajouter deux numéros et, une fois l’ajout réussi, il envoie une alerte par courrier électronique à certaines personnes. Supposons que le numéro renvoyé 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 courrier électronique lit beaucoup de configurations système et, par conséquent, diverses exceptions peuvent être émises à partir de ce bloc de code. Cependant, nous ne souhaitons pas que les exceptions rencontrées lors de la distribution des alertes se propagent à la méthode de l'appelant, car cette méthode concerne simplement la somme des deux valeurs Integer fournies. Par conséquent, le code d'envoi d'alerte par courrier électronique est placé dans un try-catch block, où Throwable est capturé et les exceptions sont simplement consignées, permettant ainsi au reste du flux de continuer.

0
CodeNewbie

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 convient de le faire:

  • Vous voulez arrêter l'application en réponse à des erreurs, en particulier AssertionError qui est par ailleurs sans danger.
  • Implémentez-vous un mécanisme de regroupement de threads similaire à ExecutorService.submit () qui vous oblige à renvoyer les exceptions à l'utilisateur pour qu'il puisse les gérer.
0
Gili

Throwable est la super-classe de toutes les erreurs et excetions. Si vous utilisez Throwable dans une clause catch, cela interceptera non seulement toutes les exceptions, mais également toutes les erreurs. Des erreurs sont générées par la machine virtuelle Java 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 hors du contrôle de l'application et ne peuvent pas être gérés. Donc, vous ne devriez pas attraper Throwables à moins d’être assez confiant dans le fait qu’il s’agit d’une exception, résidez dans Throwable.