Est-ce vraiment si mauvais d’attraper une exception générale?

Tout en analysant un code hérité avec FXCop, il m’est apparu que c’était vraiment grave d’attraper une erreur d’exception générale dans un bloc try ou de rechercher une exception spécifique. Réflexions sur une carte postale, s’il vous plaît.

Évidemment, c’est l’une de ces questions où la seule vraie réponse est “ça dépend”.

La principale chose dont il dépend est où vous attrapez l’exception. En général, les bibliothèques devraient être plus conservasortingces en ce qui concerne les exceptions, tandis qu’au niveau supérieur de votre programme (par exemple dans votre méthode principale ou en haut de la méthode d’action dans un contrôleur, etc.), vous pouvez être plus libéral.

La raison en est que, par exemple, vous ne voulez pas intercepter toutes les exceptions dans une bibliothèque, car vous pourriez masquer des problèmes qui n’ont rien à voir avec votre bibliothèque, comme “OutOfMemoryException” que vous préféreriez vraiment créer. Noté, etc. Par ailleurs, si vous parlez d’attraper des exceptions dans votre méthode main () qui intercepte l’exception, l’affiche et se ferme … eh bien, il est probablement prudent de capturer n’importe quelle exception ici.

La règle la plus importante concernant la capture de toutes les exceptions est que vous ne devez jamais avaler toutes les exceptions en silence … par exemple, quelque chose comme ceci en Java:

try { something(); } catch (Exception ex) {} 

ou ceci en Python:

 try: something() except: pass 

Parce que ces problèmes peuvent être parmi les plus difficiles à détecter.

Une bonne règle de base est que vous ne devez attraper que des exceptions que vous pouvez traiter correctement avec vous-même. Si vous ne parvenez pas à gérer complètement l’exception, vous devriez la laisser résonner à quelqu’un qui le peut.

À moins que vous ne vous connectiez et que vous ne nettoyiez le code au début de votre application, alors je pense qu’il est mauvais d’attraper toutes les exceptions.

Ma règle de base est d’attraper toutes les exceptions que vous attendez et toute autre chose est un bogue.

Si vous attrapez tout et continuez, c’est un peu comme si vous mettiez un sparadrap sur le voyant de votre tableau de bord. Vous ne pouvez plus le voir, mais cela ne signifie pas que tout va bien.

Oui! (sauf au “top” de votre application)

En capturant une exception et en permettant à l’exécution du code de continuer, vous déclarez que vous savez comment gérer et contourner, ou résoudre un problème particulier. Vous déclarez qu’il s’agit d’ une situation récupérable . Catching Exception ou SystemException signifie que vous rencontrerez des problèmes tels que des erreurs d’E / S, des erreurs de réseau, des erreurs de mémoire insuffisante, des erreurs de code manquant, le déréférencement de pointeur NULL et les préférences. C’est un mensonge de dire que vous pouvez y faire face.

Dans une application bien organisée, ces problèmes irrécupérables doivent être traités en amont de la stack.

De plus, à mesure que le code évolue, vous ne voulez pas que votre fonction intercepte une nouvelle exception ajoutée ultérieurement à une méthode appelée.

À mon avis, vous devriez prendre toutes les exceptions que vous attendez , mais cette règle s’applique à tout sauf à la logique de votre interface. Tout au long de la stack d’appels, vous devriez probablement créer un moyen d’attraper toutes les exceptions, de vous connecter / donner des commentaires aux utilisateurs et, si nécessaire et possible, de fermer les portes.

Rien n’est pire qu’une application qui tombe en panne avec un stacktrace hostile à l’utilisateur. Non seulement cela donne un aperçu (peut-être indésirable) de votre code, mais cela confond également votre utilisateur final, et parfois même les fait fuir vers une application concurrente.

Il y a eu beaucoup de discussions philosophiques (plus comme des arguments) sur ce problème. Personnellement, je pense que la pire chose à faire est d’avaler des exceptions. Le pire est de permettre à une exception de remonter à la surface où l’utilisateur obtient un mauvais écran rempli de charabia technique.

Eh bien, je ne vois aucune différence entre la capture d’une exception générale ou une exception spécifique, sauf que lorsque vous avez plusieurs blocs catch, vous pouvez réagir différemment en fonction de l’exception.

Vous allez attraper à la fois IOException et NullPointerException avec une exception générique, mais la façon dont votre programme doit réagir est probablement différente.

Je pense que le point est double.

Tout d’abord, si vous ne savez pas quelle exception s’est produite, comment pouvez-vous espérer vous en remettre? Si vous pensez qu’un utilisateur peut taper un nom de fichier incorrect, vous pouvez vous attendre à une exception FileNotFoundException et demander à l’utilisateur de réessayer. Si ce même code a généré une exception NullReferenceException et que vous avez simplement demandé à l’utilisateur de réessayer, il ne saurait pas ce qui s’est passé.

Deuxièmement, les directives FxCop se concentrent sur le code Library / Framework – toutes leurs règles ne sont pas conçues pour être applicables aux sites Web EXE ou ASP.Net. Avoir un gestionnaire d’exceptions global qui enregistrera toutes les exceptions et quittera bien l’application est une bonne chose à avoir.

Le problème avec la capture de toutes les exceptions est que vous pouvez attraper celles que vous ne vous attendez pas, ou même celles que vous ne devriez pas attraper. Le fait est qu’une exception de quelque nature que ce soit indique que quelque chose s’est mal passé et que vous devez régler le problème avant de continuer, sinon vous risquez de rencontrer des problèmes d’intégrité des données et d’autres bugs trop difficiles à détecter.

Pour donner un exemple, dans un projet, j’ai implémenté un type d’exception appelé CriticalException. Cela indique une condition d’erreur nécessitant l’intervention des développeurs et / ou du personnel administratif, faute de quoi les clients reçoivent une facturation incorrecte ou d’autres problèmes d’intégrité des données peuvent survenir. Il peut également être utilisé dans d’autres cas similaires lorsque la simple journalisation de l’exception est insuffisante et qu’une alerte par e-mail doit être envoyée.

Un autre développeur qui ne comprenait pas correctement le concept des exceptions a ensuite encapsulé du code qui pourrait potentiellement lancer cette exception dans un bloc try … catch générique qui supprimait toutes les exceptions. Heureusement, je l’ai repéré, mais cela aurait pu engendrer de sérieux problèmes, en particulier parce que la boîte de coin “très inhabituelle” qu’elle était censée attraper se révélait beaucoup plus courante que prévu.

Donc, en règle générale, la capture d’exceptions génériques est mauvaise à moins d’être certain à 100% que vous savez exactement quels types d’exceptions seront lancés et dans quelles circonstances. En cas de doute, laissez-les plutôt que le gestionnaire d’exceptions de premier niveau.

Une règle similaire ici n’est jamais de jeter des exceptions de type System.Exception. Vous (ou un autre développeur) pouvez vouloir attraper votre exception spécifique plus haut dans la stack d’appels tout en laissant passer les autres.

(Il y a toutefois un point à noter. Dans .NET 2.0, si un thread rencontre des exceptions non interceptées, il décharge l’intégralité de votre domaine d’application. Vous devez donc essayer le bloc principal d’un thread … catch block and pass toutes les exceptions interceptées à votre code de gestion des exceptions globales.)

Je voudrais jouer au défenseur du diable pour attraper une exception et la consigner et la relancer. Cela peut être nécessaire si, par exemple, vous êtes quelque part dans le code et qu’une exception inattendue se produit, vous pouvez l’attraper, consigner des informations d’état significatives qui ne seraient pas disponibles dans une simple trace de stack, puis les renvoyer aux couches supérieures. traiter avec.

La plupart du temps, il n’est pas nécessaire d’attraper une exception générale. Bien sûr, il y a des situations où vous n’avez pas le choix, mais dans ce cas, je pense qu’il est préférable de vérifier pourquoi vous devez l’attraper. Peut-être que quelque chose ne va pas dans votre conception.

Je pense qu’une bonne directive consiste à ne capturer que des exceptions spécifiques dans un cadre (de sorte que l’application hôte puisse traiter les cas extrêmes comme le remplissage du disque, etc.), mais je ne vois pas pourquoi exceptions de notre code d’application. Tout simplement, il y a des moments où vous ne voulez pas que l’application se plante, peu importe ce qui pourrait mal tourner.

Il y a deux cas d’utilisation complètement différents. Le premier est celui auquel la plupart des gens pensent, en mettant un essai / une capture autour d’une opération nécessitant une exception vérifiée. Cela ne devrait pas être un fourre-tout par tous les moyens.

La seconde, cependant, consiste à empêcher votre programme de se briser quand il pourrait continuer. Ces cas sont:

  • Le haut de tous les threads (par défaut, les exceptions disparaîtront sans laisser de trace!)
  • Dans une boucle de traitement principale que vous ne voulez jamais quitter
  • Inside a Loop traiter une liste d’objects où une défaillance ne doit pas en empêcher d’autres
  • En haut du thread “principal” – Vous pouvez contrôler un plantage ici, comme le vidage d’un peu de données sur la sortie standard lorsque vous manquez de mémoire.
  • Si vous avez un “Runner” qui exécute le code (par exemple, si quelqu’un vous ajoute un écouteur et que vous appelez le programme d’écoute), vous devez intercepter Exception pour enregistrer le problème et vous permettre de continuer à avertir les autres écouteurs.

Ces cas vous voulez TOUJOURS attraper Exception (Peut-être même Throwable parfois) afin d’attraper des erreurs de programmation / inattendues, les connecter et continuer.

Attraper une exception générale, je pense que c’est comme tenir un bâton de dynamite dans un immeuble en feu et éteindre la fusée. Cela aide pendant un court moment, mais la dynamite soufflera quand même après un certain temps.

De plus, il peut y avoir des situations où la capture d’une exception générale est nécessaire, mais uniquement à des fins de débogage. Les erreurs et les bogues doivent être corrigés et non masqués.