Pourquoi ne devrais-je pas envelopper chaque bloc dans "try" - "catch"?

430

J'ai toujours été d'avis que si une méthode peut lever une exception, il est imprudent de ne pas protéger cet appel avec un bloc try significatif.

Je viens de poster « Vous devriez TOUJOURS boucler les appels qui peuvent lancer try, catch blocks. »à cette question et on m'a dit qu'il s'agissait d'un« conseil remarquablement mauvais »- j'aimerais comprendre pourquoi.

Konrad
la source
4
Si je savais qu'une méthode lèverait une exception, je l'aurais corrigée en premier lieu. C'est parce que je ne sais pas où et pourquoi le code lèvera des exceptions que je les attrape à la source (chaque méthode - un try-catch générique). Par exemple, une équipe m'a donné une base de code avec une base de données antérieure. De nombreuses colonnes étaient manquantes et interceptées uniquement après avoir ajouté try catch dans la couche SQL. Deuxièmement, je peux enregistrer le nom de la méthode et le message, pour le débogage hors ligne, sinon je ne sais pas d'où il provient.
Chakra

Réponses:

340

Une méthode ne doit intercepter une exception que lorsqu'elle peut la gérer de manière raisonnable.

Sinon, transmettez-le, dans l'espoir qu'une méthode plus élevée dans la pile d'appels puisse la comprendre.

Comme d'autres l'ont noté, il est recommandé d'avoir un gestionnaire d'exceptions non géré (avec journalisation) au plus haut niveau de la pile d'appels pour garantir que toutes les erreurs fatales sont enregistrées.

Blé Mitch
la source
12
Il convient également de noter qu'il y a des coûts (en termes de code généré) pour les tryblocs. Il y a une bonne discussion dans "Plus efficace C ++" de Scott Meyers.
Nick Meyer
28
En fait, les tryblocs sont gratuits dans tout compilateur C moderne, cette information est datée de Nick. Je suis également en désaccord sur le fait d'avoir un gestionnaire d'exceptions de niveau supérieur, car vous perdez les informations de localité (l'endroit réel où l'instruction a échoué).
Blindy
31
@Blindly: le gestionnaire d'exceptions supérieur n'est pas là pour gérer l'exception, mais en fait pour crier à haute voix qu'il y a eu une exception non gérée, donner son message et terminer le programme de manière gracieuse (retourner 1 au lieu d'un appel à terminate) . Il s'agit plus d'un mécanisme de sécurité. En outre, try/catchsont plus ou moins gratuits lorsqu'il n'y a aucune exception. Lorsqu'il y en a un qui se propage, il consomme du temps à chaque fois qu'il est lancé et capturé, donc une chaîne de try/catchce seul retour n'est pas gratuite.
Matthieu M.
17
Je ne suis pas d'accord que vous devriez toujours vous écraser sur une exception non capturée. La conception logicielle moderne est très compartimentée, alors pourquoi punir le reste de l'application (et surtout, l'utilisateur!) Simplement parce qu'il y a eu une erreur? Plantage de la dernière chose que vous voulez faire, essayez au moins de donner à l'utilisateur une petite fenêtre de code qui lui permettra d'économiser du travail même si le reste de l'application n'est pas accessible.
Kendall Helmstetter Gelner
21
Kendall: Si une exception parvient à un gestionnaire de niveau supérieur, votre application est par définition dans un état non défini. Bien que, dans certains cas spécifiques, il puisse être utile de préserver les données de l'utilisateur (la récupération de documents de Word vient à l'esprit), le programme ne doit pas écraser de fichiers ni s'engager dans une base de données.
Hugh Brackett
136

Comme Mitch et d' autres l'ont déclaré, vous ne devriez pas attraper une exception que vous ne prévoyez pas de gérer d'une manière ou d'une autre. Vous devez considérer comment l'application va gérer systématiquement les exceptions lorsque vous la concevez. Cela conduit généralement à avoir des couches de gestion des erreurs basées sur les abstractions - par exemple, vous gérez toutes les erreurs liées à SQL dans votre code d'accès aux données afin que la partie de l'application qui interagit avec les objets de domaine ne soit pas exposée au fait qu'il est une DB sous le capot quelque part.

Il y a quelques odeurs de code liées que vous voulez absolument éviter en plus de l' odeur "tout attraper partout" .

  1. "catch, log, rethrow" : si vous voulez une journalisation basée sur la portée, alors écrivez une classe qui émet une instruction log dans son destructeur lorsque la pile se déroule à cause d'une exception (ala std::uncaught_exception()). Tout ce que vous devez faire est de déclarer une instance de journalisation dans la portée qui vous intéresse et, voila, vous avez une journalisation et pas de logique try/ inutile catch.

  2. "catch, throw traduire" : cela indique généralement un problème d'abstraction. À moins que vous n'implémentiez une solution fédérée où vous traduisez plusieurs exceptions spécifiques en une autre plus générique, vous avez probablement une couche d'abstraction inutile ... et ne dites pas que "j'en aurai peut-être besoin demain" .

  3. "catch, cleanup, rethrow" : c'est une de mes bêtes noires. Si vous voyez beaucoup de cela, alors vous devez appliquer les techniques d' acquisition de ressources est l'initialisation et placer la partie de nettoyage dans le destructeur d'une instance d'objet concierge .

Je considère que le code jonché de try/ catchblocs est une bonne cible pour la révision et la refactorisation du code. Cela indique que la gestion des exceptions n'est pas bien comprise ou que le code est devenu une amœba et a sérieusement besoin d'être refactorisé.

D.Shawley
la source
6
# 1 est nouveau pour moi. +1 pour cela. De plus, je voudrais noter une exception commune à # 2, qui est que si vous concevez souvent une bibliothèque, vous voudrez traduire les exceptions internes en quelque chose spécifié par l'interface de votre bibliothèque pour réduire le couplage (cela peut être ce que vous voulez dire par "solution fédérée", mais je ne connais pas ce terme).
rmeador
3
Fondamentalement, ce que vous avez dit: parashift.com/c++-faq-lite/exceptions.html#faq-17.13
Björn Pollex
1
# 2, où ce n'est pas une odeur de code mais qui a du sens, peut être amélioré en gardant l'ancienne exception comme imbriquée.
Déduplicateur
1
Concernant # 1: std :: uncaught_exception () vous indique qu'il y a une exception non capturée en vol, mais AFAIK seule une clause catch () vous permet de déterminer ce qu'est réellement cette exception. Ainsi, même si vous pouvez consigner le fait que vous quittez une étendue en raison d'une exception non interceptée, seul un essai / capture englobant vous permet de consigner tous les détails. Correct?
Jeremy
@Jeremy - vous avez raison. J'enregistre généralement les détails de l'exception lorsque je gère l'exception. Il est très utile d'avoir une trace des images intermédiaires. Vous devez généralement enregistrer l'identificateur de thread ou un certain contexte d'identification pour corréler les lignes de journal. J'ai utilisé une Loggerclasse similaire à log4j.Loggercelle qui inclut l'ID de thread dans chaque ligne de journal et j'ai émis un avertissement dans le destructeur lorsqu'une exception était active.
D.Shawley
48

Parce que la question suivante est "J'ai attrapé une exception, que dois-je faire ensuite?" Que vas-tu faire? Si vous ne faites rien - c'est une erreur qui se cache et le programme pourrait "ne pas fonctionner" sans aucune chance de trouver ce qui s'est passé. Vous devez comprendre ce que vous ferez exactement une fois que vous aurez pris l'exception et ne l'attraper que si vous le savez.

acéré
la source
29

Vous n'avez pas besoin de couvrir chaque bloc avec try-catches car un try-catch peut toujours intercepter les exceptions non gérées jetées dans les fonctions plus bas dans la pile des appels. Donc, plutôt que de faire en sorte que chaque fonction ait un try-catch, vous pouvez en avoir un au niveau logique supérieur de votre application. Par exemple, il pourrait y avoir une SaveDocument()routine de niveau supérieur, qui appelle de nombreuses méthodes qui appellent d' autres méthodes , etc. Ces sous-méthodes ne ont pas besoin de leurs propres essayages prises, parce que si elles jettent, il est toujours pris par SaveDocument()les prises de.

C'est bien pour trois raisons: c'est pratique car vous avez un seul endroit pour signaler une erreur: le SaveDocument()(s) bloc (s) catch. Il n'est pas nécessaire de répéter cela dans toutes les sous-méthodes, et c'est ce que vous voulez de toute façon: un seul endroit pour donner à l'utilisateur un diagnostic utile sur quelque chose qui a mal tourné.

Deuxièmement, la sauvegarde est annulée chaque fois qu'une exception est levée. Avec chaque sous-méthode essai-capture, si une exception est levée, vous obtenez pour le bloc catch de cette méthode, les feuilles d'exécution de la fonction, et il exerce à travers SaveDocument(). Si quelque chose a déjà mal tourné, vous voudrez probablement vous arrêter là.

Troisièmement, toutes vos sous-méthodes peuvent supposer que chaque appel réussit . Si un appel échoue, l'exécution passe au bloc catch et le code suivant n'est jamais exécuté. Cela peut rendre votre code beaucoup plus propre. Par exemple, voici les codes d'erreur:

int ret = SaveFirstSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveSecondSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveThirdSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

Voici comment cela pourrait être écrit avec des exceptions:

// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();

Maintenant, ce qui se passe est beaucoup plus clair.

Notez que le code protégé contre les exceptions peut être plus difficile à écrire de différentes manières: vous ne voulez pas perdre de mémoire si une exception est levée. Assurez-vous que vous connaissez RAII , conteneurs STL, pointeurs intelligents et autres objets qui libèrent leurs ressources dans les destructeurs, car les objets sont toujours détruits avant les exceptions.

AshleysBrain
la source
2
Splendides exemples. Ouais, attrapez le plus haut possible, en unités logiques, comme autour d'une opération 'transactionnelle' comme un chargement / sauvegarde / etc. Rien ne semble pire que du code parsemé de blocs répétitifs et redondants try- catchqui tentent de signaler chaque permutation légèrement différente d'une erreur avec un message légèrement différent, alors qu'en réalité, ils devraient tous se terminer de la même manière: échec de transaction ou de programme et sortie! Si un échec digne d'une exception se produit, je parie que la plupart des utilisateurs veulent simplement récupérer ce qu'ils peuvent ou, au moins, être laissés seuls sans avoir à traiter 10 niveaux de message à ce sujet.
underscore_d
Je voulais juste dire que c'est l'une des meilleures explications "lancer tôt, attraper tard" que j'ai jamais lues: concises et les exemples illustrent parfaitement vos points. Je vous remercie!
corderazo00
27

Herb Sutter a écrit sur ce problème ici . Pour sûr vaut la peine d'être lu.
Un teaser:

"L'écriture de code d'exception est fondamentalement sur l'écriture de" try "et" catch "aux bons endroits." Discuter.

Autrement dit, cette déclaration reflète une incompréhension fondamentale de la sécurité d'exception. Les exceptions ne sont qu'une autre forme de rapport d'erreurs, et nous savons certainement que l'écriture de code sans erreur ne consiste pas seulement à vérifier les codes de retour et à gérer les conditions d'erreur.

En fait, il s'avère que la sécurité des exceptions consiste rarement à écrire «essayer» et «attraper» - et le plus rarement le mieux. N'oubliez pas non plus que la sécurité des exceptions affecte la conception d'un code; ce n'est jamais juste une réflexion après coup qui peut être modifiée avec quelques déclarations de capture supplémentaires comme pour l'assaisonnement.

Tadeusz Kopec
la source
15

Comme indiqué dans d'autres réponses, vous ne devez intercepter une exception que si vous pouvez effectuer une sorte de gestion d'erreurs sensible pour cela.

Par exemple, dans la question qui a généré votre question, l'interrogateur demande s'il est sûr d'ignorer les exceptions pour un lexical_castd'un entier à une chaîne. Un tel casting ne devrait jamais échouer. S'il a échoué, quelque chose a terriblement mal tourné dans le programme. Que pourriez-vous faire pour récupérer dans cette situation? Il est probablement préférable de laisser le programme mourir, car il est dans un état auquel on ne peut pas faire confiance. Donc, ne pas gérer l'exception peut être la chose la plus sûre à faire.

Kristopher Johnson
la source
12

Si vous gérez toujours les exceptions immédiatement dans l'appelant d'une méthode qui peut lever une exception, les exceptions deviennent inutiles et vous feriez mieux d'utiliser des codes d'erreur.

Le point entier des exceptions est qu'elles n'ont pas besoin d'être gérées dans toutes les méthodes de la chaîne d'appel.

starblue
la source
9

Le meilleur conseil que j'ai entendu est que vous ne devez jamais intercepter les exceptions qu'aux points où vous pouvez raisonnablement faire quelque chose au sujet de la condition exceptionnelle, et que "capturer, enregistrer et libérer" n'est pas une bonne stratégie (si cela est parfois inévitable dans les bibliothèques).

Associés Donal
la source
2
@KeithB: Je considérerais cela comme une deuxième meilleure stratégie. C'est mieux si vous pouvez obtenir le journal écrit d'une autre manière.
David Thornley
1
@KeithB: C'est une stratégie "mieux que rien dans une bibliothèque". "Attrapez, connectez-vous, traitez-le correctement" est préférable dans la mesure du possible. (Ouais, je sais que ce n'est pas toujours possible.)
Donal Fellows
6

Je suis d'accord avec l'orientation de base de votre question pour gérer autant d'exceptions que possible au niveau le plus bas.

Une partie de la réponse existante dit "Vous n'avez pas besoin de gérer l'exception. Quelqu'un d'autre le fera dans la pile". D'après mon expérience, c'est une mauvaise excuse pour ne pas penser à la gestion des exceptions au niveau du morceau de code actuellement développé, faisant de l'exception la gestion du problème de quelqu'un d'autre ou d'une version ultérieure.

Ce problème se développe considérablement dans le développement distribué, où vous devrez peut-être appeler une méthode implémentée par un collègue. Et puis vous devez inspecter une chaîne imbriquée d'appels de méthode pour savoir pourquoi il / elle vous lance une exception, qui aurait pu être gérée beaucoup plus facilement avec la méthode imbriquée la plus profonde.

Bananeweizen
la source
5

Le conseil que mon professeur d'informatique m'a donné une fois était: "N'utilisez les blocs Try and Catch que lorsqu'il n'est pas possible de gérer l'erreur en utilisant des moyens standard."

À titre d'exemple, il nous a dit que si un programme rencontrait un problème grave dans un endroit où il n'était pas possible de faire quelque chose comme:

int f()
{
    // Do stuff

    if (condition == false)
        return -1;
    return 0;
}

int condition = f();

if (f != 0)
{
    // handle error
}

Ensuite, vous devriez utiliser les blocs try, catch. Bien que vous puissiez utiliser des exceptions pour gérer cela, ce n'est généralement pas recommandé car les exceptions sont coûteuses en termes de performances.

Mike Bailey
la source
7
C'est une stratégie, mais beaucoup de gens recommandent de ne jamais retourner les codes d'erreur ou les états d'échec / de succès des fonctions, en utilisant des exceptions à la place. La gestion des erreurs basée sur les exceptions est souvent plus facile à lire que le code basé sur les codes d'erreur. (Voir la réponse d'AshleysBrain à cette question pour un exemple.) Rappelez-vous également que de nombreux professeurs d'informatique ont très peu d'expérience dans l'écriture de code réel.
Kristopher Johnson
1
-1 @Sagelika Votre réponse consiste à éviter les exceptions, donc pas besoin de try-catch.
Vicente Botet Escriba
3
@Kristopher: Un autre gros inconvénient du code retour est qu'il est vraiment facile d'oublier de vérifier un code retour, et juste après l'appel n'est pas nécessairement le meilleur endroit pour gérer le problème.
David Thornley
ehh, cela dépend, mais dans de nombreux cas (en mettant de côté les gens qui lancent quand ils ne devraient vraiment pas), les exceptions sont supérieures aux codes de retour pour de nombreuses raisons. dans la plupart des cas, l'idée que les exceptions sont préjudiciables aux performances est un grand ol '[citation nécessaire]
underscore_d
3

Si vous souhaitez tester le résultat de chaque fonction, utilisez des codes retour.

Le but des exceptions est que vous puissiez tester les résultats MOINS souvent. L'idée est de séparer les conditions exceptionnelles (inhabituelles, plus rares) de votre code plus ordinaire. Cela permet de garder le code ordinaire plus propre et plus simple - mais toujours capable de gérer ces conditions exceptionnelles.

Dans un code bien conçu, des fonctions plus profondes peuvent se déclencher et des fonctions plus élevées peuvent intercepter. Mais la clé est que de nombreuses fonctions "intermédiaires" seront libérées de la charge de gérer des conditions exceptionnelles. Ils doivent seulement être "exceptionnels", ce qui ne signifie pas qu'ils doivent attraper.

bluedog
la source
2

Je voudrais ajouter à cette discussion que, depuis C ++ 11 , cela a beaucoup de sens, tant que chaque catchbloc rethrowest l'exception jusqu'au point où il peut / doit être géré. De cette façon, une trace peut être générée . Je pense donc que les avis précédents sont en partie dépassés.

Utiliser std::nested_exceptionetstd::throw_with_nested

Il est décrit sur StackOverflow ici et ici comment y parvenir.

Puisque vous pouvez le faire avec n'importe quelle classe d'exception dérivée, vous pouvez ajouter beaucoup d'informations à une telle trace! Vous pouvez également jeter un oeil à mon MWE sur GitHub , où une trace ressemblerait à quelque chose comme ceci:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
GPMueller
la source
2

J'ai eu "l'opportunité" de récupérer plusieurs projets et les cadres ont remplacé toute l'équipe de développement car l'application avait trop d'erreurs et les utilisateurs étaient fatigués des problèmes et des contournements. Ces bases de code avaient toutes une gestion centralisée des erreurs au niveau de l'application, comme le décrit la réponse la plus votée. Si cette réponse est la meilleure pratique, pourquoi cela n'a-t-il pas fonctionné et a-t-il permis à l'équipe de développement précédente de résoudre les problèmes? Peut-être que parfois cela ne fonctionne pas? Les réponses ci-dessus ne mentionnent pas combien de temps les développeurs passent à résoudre des problèmes uniques. Si le temps de résolution des problèmes est la mesure clé, l'instrumentation du code avec les blocs try..catch est une meilleure pratique.

Comment mon équipe a-t-elle résolu les problèmes sans modifier de manière significative l'interface utilisateur? Simple, chaque méthode a été instrumentée avec try..catch bloqué et tout a été enregistré au point d'échec avec le nom de la méthode, les valeurs des paramètres de méthode concaténées dans une chaîne transmise avec le message d'erreur, le message d'erreur, le nom de l'application, la date, et version. Avec ces informations, les développeurs peuvent exécuter des analyses sur les erreurs pour identifier l'exception qui se produit le plus! Ou l'espace de noms avec le plus grand nombre d'erreurs. Il peut également valider qu'une erreur qui se produit dans un module est correctement gérée et n'est pas causée par plusieurs raisons.

Un autre avantage pro de ceci est que les développeurs peuvent définir un point d'arrêt dans la méthode de journalisation des erreurs et avec un point d'arrêt et un simple clic sur le bouton de débogage "step out", ils sont dans la méthode qui a échoué avec un accès complet au réel objets au point de défaillance, facilement accessibles dans la fenêtre immédiate. Il facilite le débogage et permet de faire glisser l'exécution vers le début de la méthode pour dupliquer le problème et trouver la ligne exacte. La gestion centralisée des exceptions permet-elle à un développeur de répliquer une exception en 30 secondes? Non.

L'instruction "Une méthode ne doit intercepter une exception que lorsqu'elle peut la gérer de manière raisonnable." Cela implique que les développeurs peuvent prévoir ou rencontreront toutes les erreurs pouvant survenir avant la publication. Si cela était vrai à un niveau supérieur, le gestionnaire d'exceptions d'application ne serait pas nécessaire et il n'y aurait pas de marché pour Elastic Search et logstash.

Cette approche permet également aux développeurs de trouver et de résoudre les problèmes intermittents en production! Souhaitez-vous déboguer sans débogueur en production? Ou préférez-vous prendre des appels et recevoir des courriels d'utilisateurs en colère? Cela vous permet de résoudre les problèmes avant que quiconque ne le sache et sans avoir à envoyer un courrier électronique, une messagerie instantanée ou Slack avec le support, car tout le nécessaire pour résoudre le problème est là. 95% des numéros n'ont jamais besoin d'être reproduits.

Pour fonctionner correctement, il doit être combiné avec une journalisation centralisée qui peut capturer l'espace de nom / module, le nom de classe, la méthode, les entrées et le message d'erreur et le stocker dans une base de données afin qu'il puisse être agrégé pour mettre en évidence la méthode qui échoue le plus afin qu'elle puisse être fixe en premier.

Parfois, les développeurs choisissent de lever des exceptions dans la pile à partir d'un bloc catch, mais cette approche est 100 fois plus lente que le code normal qui ne lève pas. La capture et la libération avec journalisation sont préférées.

Cette technique a été utilisée pour stabiliser rapidement une application qui échouait toutes les heures pour la plupart des utilisateurs d'une entreprise Fortune 500 développée par 12 développeurs sur 2 ans. À l'aide de ces 3000 exceptions différentes ont été identifiées, corrigées, testées et déployées en 4 mois. Cela correspond en moyenne à un correctif toutes les 15 minutes en moyenne pendant 4 mois.

Je suis d'accord que ce n'est pas amusant de taper tout ce qui est nécessaire pour instrumenter le code et je préfère ne pas regarder le code répétitif, mais ajouter 4 lignes de code à chaque méthode en vaut la peine à long terme.

user2502917
la source
1
Envelopper chaque bloc semble exagéré. Cela rend rapidement votre code gonflé et douloureux à lire. La journalisation d'une trace de pile à partir d'une exception à des niveaux supérieurs vous montre où le problème s'est produit et qui, combiné à l'erreur elle-même, est généralement suffisamment d'informations pour continuer. Je serais curieux de savoir où vous avez trouvé cela insuffisant. Juste pour que je puisse acquérir l'expérience de quelqu'un d'autre.
user441521
1
"Les exceptions sont 100 à 1000 fois plus lentes que le code normal et ne devraient jamais être renvoyées" - cette affirmation n'est pas vraie sur la plupart des compilateurs et du matériel modernes.
Mitch Wheat
Cela semble exagéré et nécessite un peu de frappe, mais c'est le seul moyen d'effectuer des analyses sur les exceptions pour trouver et corriger d'abord les plus grosses erreurs, y compris les erreurs intermittentes en production. Le bloc catch gère les erreurs spécifiques si nécessaire et possède une seule ligne de code qui enregistre.
user2502917
Non, les exceptions sont très lentes. L'alternative est les codes de retour, les objets ou les variables. Voir ce post de débordement de pile ... "les exceptions sont au moins 30 000 fois plus lentes que les codes de retour" stackoverflow.com/questions/891217/…
user2502917
1

Outre les conseils ci-dessus, j'utilise personnellement certains try + catch + throw; pour la raison suivante:

  1. Aux limites de différents codeurs, j'utilise try + catch + throw dans le code écrit par moi-même, avant que l'exception ne soit lancée à l'appelant qui est écrite par d'autres, cela me donne une chance de connaître une condition d'erreur survenue dans mon code, et cet endroit est beaucoup plus proche du code qui lève initialement l'exception, plus il est proche, plus il est facile de trouver la raison.
  2. A la limite des modules, bien que des modules différents puissent être écrits ma même personne.
  3. Objectif Learning + Debug, dans ce cas j'utilise catch (...) en C ++ et catch (Exception ex) en C #, pour C ++, la bibliothèque standard ne lève pas trop d'exceptions, donc ce cas est rare en C ++. Mais un lieu commun en C #, C # a une énorme bibliothèque et une hiérarchie d'exceptions mature, le code de la bibliothèque C # lève des tonnes d'exceptions, en théorie, je (et vous) devriez connaître toutes les exceptions de la fonction que vous avez appelée, et connaître la raison / cas pourquoi ces exceptions étant levées, et savent comment les gérer (passer ou attraper et gérer en place) avec grâce. Malheureusement, en réalité, il est très difficile de tout savoir sur les exceptions potentielles avant d'écrire une ligne de code. Donc, j'attrape tout et laisse mon code s'exprimer à voix haute en se connectant (dans l'environnement du produit) / Assert dialog (dans l'environnement de développement) lorsqu'une exception se produit vraiment. De cette façon, j'ajoute progressivement du code de gestion des exceptions. Je le connais conflit avec de bons conseils mais en réalité ça marche pour moi et je ne connais pas de meilleur moyen pour ce problème.
zhaorufei
la source
1

Je me sens obligé d'ajouter une autre réponse bien que la réponse de Mike Wheat résume assez bien les points principaux. Je pense à ça comme ça. Lorsque vous avez des méthodes qui font plusieurs choses, vous multipliez la complexité, pas en l'ajoutant.

En d'autres termes, une méthode qui est enveloppée dans un catch try a deux résultats possibles. Vous avez le résultat de non-exception et le résultat d'exception. Lorsque vous avez affaire à de nombreuses méthodes, cela explose de façon exponentielle au-delà de la compréhension.

Exponentiellement parce que si chaque méthode se ramifie de deux manières différentes, chaque fois que vous appelez une autre méthode, vous équerrez le nombre précédent de résultats potentiels. Au moment où vous avez appelé cinq méthodes, vous avez au moins 256 résultats possibles au minimum. Comparez cela à ne pas faire de try / catch dans chaque méthode et vous n'avez qu'un seul chemin à suivre.

Voilà essentiellement comment je le vois. Vous pourriez être tenté de prétendre que tout type de branchement fait la même chose, mais try / catches est un cas particulier car l'état de l'application devient fondamentalement indéfini.

Donc, en bref, try / catches rend le code beaucoup plus difficile à comprendre.

user875234
la source
-2

Vous n'avez pas besoin de couvrir chaque partie de votre code à l'intérieur try-catch. L'utilisation principale du try-catchbloc est la gestion des erreurs et les bugs / exceptions dans votre programme. Quelques utilisations de try-catch-

  1. Vous pouvez utiliser ce bloc où vous souhaitez gérer une exception ou simplement vous pouvez dire que le bloc de code écrit peut lever une exception.
  2. Si vous souhaitez disposer vos objets immédiatement après leur utilisation, vous pouvez utiliser le try-catchbloc.
Amit Kumawat
la source
1
"Si vous souhaitez disposer vos objets immédiatement après leur utilisation, vous pouvez utiliser le bloc try-catch." Aviez-vous l'intention de promouvoir RAII / durée de vie minimale des objets? Si oui, eh bien, try/ catchest complètement séparé / orthogonal de cela. Si vous souhaitez disposer des objets dans une portée plus petite, vous pouvez simplement en ouvrir un nouveau { Block likeThis; /* <- that object is destroyed here -> */ }- pas besoin d'envelopper try/ catchsauf si vous avez réellement besoin de catchquoi que ce soit, bien sûr.
underscore_d
# 2 - La suppression d'objets (qui ont été créés manuellement) dans l'exception me semble bizarre, cela peut être utile dans certaines langues sans doute, mais généralement vous le faites dans un essai / enfin "dans le bloc try / except", et non spécifiquement dans le bloc except lui-même - puisque l'objet lui-même peut avoir été la cause de l'exception en premier lieu, et donc provoquer une autre exception et potentiellement un crash.
TS