web-dev-qa-db-fra.com

Plusieurs ou une seule tentative de capture

Je travaille à nettoyer une partie de mon code et je suis arrivé à un point où je ne savais pas quel itinéraire serait le meilleur.

Actuellement, j'ai un seul bloc catch try sur la majorité de ma méthode et il gère quelques exceptions distinctes à la fin, mais je me suis dit qu'avoir plus de blocs catch catch serait mieux pour la maintenance. Cependant, en décomposant le code, j'en suis arrivé à écrire des blocs pour le même type d'exception. Je peux voir le bon côté pour écrire un bloc pour chaque partie puisque je peux ensuite donner plus de détails sur la raison de son échec.

Ma question est la suivante ... existe-t-il un inconvénient à cela? Pourrait-il y avoir des problèmes de performances ou un autre monstre caché que je ne vois pas?

En outre, quelle est la méthode préférée pour gérer plusieurs exceptions dans une méthode, existe-t-il une norme de l'industrie? 

Juste pour mieux illustrer mon propos, voici un pseudo-code

//multiple try catch for same exception
try {
     //some code here
} catch (MyException e) {
     //specific error message here
}
try {
     //some different code here
} catch (MyException e) {
     //more specific error message indicating a different issue
}
47
Shaded

J'essaie toujours de réduire les niveaux d'imbrication pour la lisibilité et la maintenabilité. Si vous avez n blocs try/catch, chacun gérant le même type d'exception, pourquoi ne pas refactoriser le code qui peut renvoyer l'exception dans des méthodes ... cela ressemblerait à ceci:

try {
    firstBatchOfTricky();
    secondBatchOfTricky();
    ....
    nthBatchOfTricky();
} catch (ItWentBoomException e) {
   // recover from boom
} catch (ItWentBangException e) {
   // recover from bang
}

Ceci est beaucoup plus lisible que d'avoir plusieurs tentatives/captures. Notez que vos méthodes doivent décrire ce qu’elles font dans l’esprit de code auto-documentant.

Puisque vous avez votre propre type d’exception, vous pouvez ajouter les données nécessaires à l’exception pour effectuer différentes opérations dans le bloc catch. Lorsque vous dites "message plus spécifique", vous pouvez simplement lancer l'exception avec le message détaillé; vous ne devriez pas avoir besoin de plusieurs blocs catch. Si vous voulez faire des choses radicalement différentes en fonction de l'état de l'exception, créez simplement plus de types d'exceptions et de blocs catch, mais un seul bloc try, comme le montre mon pseudo-code ...

Enfin, si vous ne pouvez pas récupérer d'exception, vous ne devez pas encombrer le code avec des blocs catch. Lancez une exception d'exécution et laissez-la bouillonner. (Bon conseil de @tony dans les commentaires)

50
hvgotcodes

Ce n’est pas une question de performance ou de préférences personnelles: c’est une question de fonctionnalité et d’exigences.

Supposons que j'écris:

Scénario 1:

try
{
  doThingA();
}
catch (SomeException panic)
{
  System.out.println("doThingA failed");
}
try
{
  doThingB();
}
catch (SomeException panic)
{
  System.out.println("doThingB failed");
}

Scénario 2:

try
{
  doThingA();
  doThingB();
}
catch (SomeException panic)
{
  System.out.println("doThingA or doThingB failed");
}

Ces deux scénarios ne sont pas équivalents: ils font des choses différentes. Dans le scénario 1, si doThingA lève l'exception, doThingB est toujours exécuté. Dans le scénario 2, si doThingA lève l'exception, doThingB n'est pas exécuté. La question n'est donc pas de savoir si les performances sont meilleures ou si le code est plus lisible, mais si doThingA échoue, doThingB doit-il toujours être exécuté ou non?

Si ce que vous voulez vraiment est le deuxième comportement, mais que vous voulez que des messages différents informent l’utilisateur de ce qui ne va pas, lancez différentes exceptions ou insérez le texte du message dans l’exception, c.-à-d.

void doThingA() throws SomeException
{
  ... whatever code ...
  if (theWorldIsAboutToEnd)
    throw new SomeException("doThingA failed");
}

Ensuite, dans la clause catch, au lieu d'afficher une chaîne constante, affichez SomeException.toString ou SomeException.getMessage.

43
Jay

Si les exceptions peuvent être gérées différemment (message d'erreur différent, etc.), il est préférable de les récupérer séparément. 

Si les types d'exception sont différents, cela ne signifie pas que vous devez avoir des blocs try distincts, vous pouvez avoir un bloc try avec plusieurs captures.

4
jzd

C'est totalement dépendant du scénario. Si vous faites un tas de choses qui lève une exception de sécurité et que vous gérez ce scénario de la même manière, vous pouvez utiliser un bloc try pour cela.

Cependant, cela dit, utiliser de nombreux blocs try/catch plus petits est souvent préférable à mon avis. Utiliser un gros essai/attraper revient à utiliser plusieurs instructions goto, sauf que vous ne pouvez pas dire d'où viennent les gotos.

Par exemple, dans la liste ci-dessous, comment savoir quelle méthode irait à l'exception1 et laquelle irait à l'exception 2? C'est bien si c'est un petit bloc, mais une fois qu'il devient plus grand, il devient très illisible.

try{
  doThing1();
  doThing2();
  doThing3();
  doThing4();
  doThing5();
  doThing6();
  doThing7();
  doThing8();
  doThing9();
} catch (Exception1 e){

} catch (Exception2 e){

}

Ci-dessous est plus clair.

try{
  doThing1();      
} catch (Exception1 e){ [...] } 
  doThing2();
  doThing3();
  doThing4();
  doThing5();
  doThing6();
  doThing7();
  doThing8();
try{
    doThing9();
} catch (Exception2 e){ [...] }
1
JasonG

Ma préférence personnelle est un seul essai qui peut ou non avoir plusieurs blocs d'arrêt. Mes méthodes ont tendance à être assez petites là où cela a du sens. Si vous tardez trop pour que cela soit pratique, vous devrez peut-être réfléchir à la refactorisation.

Une chose à propos des blocs catch: si votre bloc catch imprime ou enregistre la trace de la pile et les relance, je dirais que vous feriez mieux d’ajouter l’exception à la clause throws de la signature de la méthode et de la laisser bouillonner. 

1
duffymo

Je suis d'accord avec le consensus général des réponses ci-dessus, qu'un seul bloc try-catch est préférable. Cependant, au moment où votre méthode est suffisamment longue pour que vous examiniez cette question, elle est probablement trop longue. Et il peut être plus facile d’en extraire de nouvelles méthodes si le traitement des exceptions est plus localisé. Néanmoins, je pense que votre meilleur choix peut être d'extraire des méthodes qui jettent simplement l'exception et laissent la gestion de l'exception en place, dans la méthode d'origine - idéalement dans un bloc try-catch unique.

1
Carl Manaster

Il semble très vieille question. Mais ma réponse la rendrait relavent car, ces derniers jours, Java 7 a ajouté une nouvelle fonctionnalité permettant d’ajouter plusieurs exceptions et le bloc catch. Cela éliminerait beaucoup de code et semblerait très intéressant. Je tombe sur cette explication de link sur le concept try-with-resource .

0
Krishna

Excellente question. Je vais dire que vous devriez utiliser un seul bloc try-catch. Mon raisonnement: si vous avez des raisons de partitionner votre méthode en plusieurs blocs try-catch, vous devriez probablement penser à refactoriser votre méthode en plusieurs méthodes, chacune avec son propre bloc try-catch.

0
Bob Kaufman

Pour des raisons de sécurité, utilisez toujours des blocs catch individuels pour chaque instruction de lancement d'exception, car si vous écrivez un bloc try en même temps, les instructions écrites ci-dessous ne seront pas exécutées.

0
Deepak Vajpayee

J'essaie d'éviter de répéter le code chaque fois que possible. Donc, si la réponse à un certain type d’exception est la même, saisissez-la une fois.

0
BigMac66

Je préfère un seul bloc try-catch. Si la longueur de la méthode augmente beaucoup, je préfère diviser la méthode en plusieurs méthodes internes pour la modularité.
Vous pourrez également parfois réutiliser ces méthodes internes.
Je me sens ainsi beaucoup plus propre et mieux pour la maintenance.

0
Swift-Tuttle

Cela dépend de votre logique de code - pouvez-vous interrompre votre processus (calcul ou autre) à tout moment ou vous pouvez/devriez/devez/devez contrôler le flux et annuler/notifier/vérifier/que vous fassiez si une condition d'erreur est indiquée par une exception à une étape donnée .

Si vous implémentez un simple client RSS, vous pouvez conserver tout le code relatif aux sockets dans un bloc. Mais si vous écrivez un client bittorrent, vous aurez besoin d’une machine à états et d’un traitement beaucoup plus granulaire des exceptions.

0
tomash