Question

En analysant du code existant avec FXCop, je me suis rendu compte si c'était vraiment si grave de détecter une erreur d'exception générale dans un bloc try ou si vous recherchiez une exception spécifique.Des pensées sur une carte postale s'il vous plaît.

Était-ce utile?

La solution

Il s’agit évidemment d’une de ces questions pour lesquelles la seule vraie réponse est « ça dépend ».

La principale chose dont cela dépend est de savoir où vous détectez l'exception.En général, les bibliothèques devraient être plus conservatrices en matière de détection des exceptions alors qu'au niveau supérieur de votre programme (par ex.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 avec ce que vous attrapez.

La raison en est que, par ex.vous ne voulez pas détecter toutes les exceptions dans une bibliothèque car vous risquez de masquer des problèmes qui n'ont rien à voir avec votre bibliothèque, comme "OutOfMemoryException" que vous préféreriez vraiment faire apparaître des bulles afin que l'utilisateur puisse être averti, etc.D'un autre côté, si vous parlez de détecter des exceptions dans votre méthode main() qui intercepte l'exception, l'affiche puis se termine...eh bien, il est probablement prudent d'attraper à peu près n'importe quelle exception ici.

La règle la plus importante pour détecter toutes les exceptions est que vous ne devez jamais avaler toutes les exceptions en silence...par exemple.quelque chose comme ça 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 détecter que les exceptions que vous pouvez gérer correctement vous-même.Si vous ne pouvez pas gérer complètement l'exception, vous devriez la laisser remonter à quelqu'un qui le peut.

Autres conseils

À moins que vous n'effectuiez une journalisation et un nettoyage du code dans le front-end de votre application, je pense qu'il est mauvais de détecter toutes les exceptions.

Ma règle de base est de détecter toutes les exceptions auxquelles vous vous attendez et tout le reste est un bug.

Si vous captez tout et continuez, c'est un peu comme mettre un pansement adhésif sur le voyant d'avertissement du tableau de bord de votre voiture.Vous ne pouvez plus le voir, mais cela ne veut pas dire que tout va bien.

Oui!(sauf en "haut" de votre candidature)

En interceptant une exception et en autorisant la poursuite de l'exécution du code, vous déclarez que vous savez comment gérer et contourner, ou résoudre un problème particulier.Vous dites que c'est une situation récupérable.Catching Exception ou SystemException signifie que vous détecterez des problèmes tels que les erreurs d'E/S, les erreurs réseau, les erreurs de mémoire insuffisante, les erreurs de code manquant, le déréférencement de pointeur nul, etc.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 haut de la pile.

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

À mon avis, vous devriez détecter toutes les exceptions. attendre, mais cette règle s'applique à tout sauf à la logique de votre interface.Tout au long de la pile d'appels, vous devriez probablement créer un moyen d'intercepter toutes les exceptions, effectuer une journalisation/donner des commentaires aux utilisateurs et, si nécessaire et possible, arrêter correctement.

Rien n'est pire qu'une application qui plante avec une trace de pile peu conviviale affichée à l'écran.Non seulement cela donne un aperçu (peut-être indésirable) de votre code, mais cela confond également votre utilisateur final et le fait parfois même fuir vers une application concurrente.

Il y a eu beaucoup de discussions philosophiques (plutôt des arguments) sur cette question.Personnellement, je pense que la pire chose que l’on puisse faire est d’avaler des exceptions.Le pire suivant est de permettre à une exception de remonter à la surface où l'utilisateur obtient un écran méchant plein de charabia technique.

Le problème est double je pense.

Premièrement, si vous ne savez pas quelle exception s'est produite, comment pouvez-vous espérer vous en remettre.Si vous vous attendez à ce qu'un utilisateur tape un nom de fichier incorrect, vous pouvez vous attendre à une exception FileNotFoundException et demander à l'utilisateur de réessayer.Si ce même code générait une NullReferenceException et que vous disiez simplement à 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.Donc, avoir un gestionnaire d'exceptions global qui enregistrera toutes les exceptions et quittera correctement l'application est une bonne chose.

Le problème avec la capture de toutes les exceptions est que vous pouvez détecter celles auxquelles vous ne vous attendez pas, ou même celles auxquelles vous devriez pas être attrapant.Le fait est qu'une exception de quelque nature que ce soit indique que quelque chose ne va pas et que vous devez régler le problème avant de continuer, sinon vous risquez de vous retrouver avec des problèmes d'intégrité des données et d'autres bugs qui ne sont pas si faciles à 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 qui nécessite l'intervention des développeurs et/ou du personnel administratif, sinon les clients seront facturés de manière incorrecte ou d'autres problèmes d'intégrité des données pourraient en résulter.Il peut également être utilisé dans d'autres cas similaires lorsque la simple journalisation de l'exception n'est pas suffisante et qu'une alerte par e-mail doit être envoyée.

Un autre développeur qui n'a pas bien compris le concept d'exceptions a ensuite encapsulé du code susceptible de générer 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 entraîner de sérieux problèmes, d'autant plus que le cas de coin "très rare" qu'il était censé attraper s'est avéré beaucoup plus courant que prévu.

Donc, en général, détecter les exceptions génériques est mauvais à moins que vous ne soyez sûr à 100 % de savoir exactement quels types d'exceptions seront levées et dans quelles circonstances.En cas de doute, laissez-les plutôt remonter au gestionnaire d’exceptions de niveau supérieur.

Une règle similaire ici est de ne jamais lancer d'exceptions de type System.Exception.Vous (ou un autre développeur) souhaiterez peut-être intercepter votre exception spécifique plus haut dans la pile d'appels tout en laissant les autres passer.

(Il y a cependant 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 envelopper le corps principal d'un thread dans un bloc try...catch générique et transmettre toutes les exceptions qui y sont capturées à votre code de gestion globale des exceptions.)

Eh bien, je ne vois aucune différence entre intercepter une exception générale ou une exception spécifique, sauf que lorsque vous avez plusieurs blocs catch, vous pouvez réagir différemment selon la nature de l'exception.

En conclusion, vous attraperez les deux IOException et NullPointerException avec un générique Exception, mais la façon dont votre programme doit réagir est probablement différente.

Je voudrais jouer l'avocat du diable pour attraper Exception, l'enregistrer et le 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'intercepter, enregistrer des informations d'état significatives qui ne seraient pas disponibles dans une simple trace de pile, puis les renvoyer aux couches supérieures pour traiter avec.

Il existe deux cas d’utilisation complètement différents.La première est celle à laquelle la plupart des gens pensent, mettre en place un try/catch autour d'une opération qui nécessite une exception vérifiée.Cela ne devrait en aucun cas être un fourre-tout.

La seconde, cependant, est d'empêcher votre programme de s'interrompre alors qu'il pourrait continuer.Ces cas sont :

  • Le sommet de tous les fils de discussion (par défaut, les exceptions disparaîtront sans laisser de trace !)
  • À l'intérieur d'une boucle de traitement principale dont vous prévoyez de ne jamais sortir
  • À l'intérieur d'une boucle traitant une liste d'objets où un échec ne devrait pas en arrêter d'autres
  • Haut du fil de discussion "principal" - Vous pouvez contrôler un crash ici, comme vider un peu de données sur la sortie standard lorsque vous manquez de mémoire.
  • Si vous avez un "Runner" qui exécute du code (par exemple, si quelqu'un vous ajoute un écouteur et que vous appelez l'écouteur), alors lorsque vous exécutez le code, vous devez intercepter Exception pour enregistrer le problème et vous permettre de continuer à notifier les autres auditeurs.

Dans ces cas, vous voulez TOUJOURS intercepter une exception (peut-être même parfois jetable) afin d'attraper des erreurs de programmation/inattendues, de les enregistrer et de continuer.

Je pense qu'une bonne ligne directrice est de détecter uniquement les exceptions spécifiques dans un cadre (afin que l'application hôte puisse gérer des cas extrêmes comme le remplissage du disque, etc.), mais je ne vois pas pourquoi nous ne devrions pas pouvoir tout capturer. exceptions à notre code d'application.Il y a tout simplement des moments où vous ne voulez pas que l'application plante, peu importe ce qui pourrait mal se passer.

La plupart du temps, il n’est pas nécessaire de détecter 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 vaut mieux vérifier pourquoi vous devez l'attraper.Il y a peut-être quelque chose qui ne va pas dans votre conception.

Attraper une exception générale, j'ai l'impression que c'est comme tenir un bâton de dynamite à l'intérieur d'un bâtiment en feu et éteindre la fusée.Cela aide pendant un court moment, mais la dynamite explosera de toute façon après un certain temps.

Bien sûr, il peut y avoir des situations où la détection d'une exception générale est nécessaire, mais uniquement à des fins de débogage.Les erreurs et les bugs doivent être corrigés et non masqués.

Pour ma classe IabManager, que j'ai utilisée avec la facturation in-app (à partir de l'exemple TrivialDrive en ligne), j'ai remarqué que je faisais parfois face à de nombreuses exceptions.C’en est arrivé au point où c’est devenu imprévisible.

J'ai réalisé que, tant que j'arrêtais d'essayer de consommer un produit intégré à l'application après qu'une exception se produise, c'est là que se produiraient la plupart des exceptions (en consommation, par opposition à l'achat), je serais en sécurité.

Je viens de changer toutes les exceptions en une exception générale, et maintenant je n'ai plus à m'inquiéter de la levée d'autres exceptions aléatoires et imprévisibles.

Avant:

    catch (final RemoteException exc)
    {
        exc.printStackTrace();
    }
    catch (final IntentSender.SendIntentException exc)
    {
        exc.printStackTrace();
    }
    catch (final IabHelper.IabAsyncInProgressException exc)
    {
        exc.printStackTrace();
    }
    catch (final NullPointerException exc)
    {
        exc.printStackTrace();
    }
    catch (final IllegalStateException exc)
    {
        exc.printStackTrace();
    }

Après:

    catch (final Exception exc)
    {
        exc.printStackTrace();
    }

Avis impopulaire :Pas vraiment.

Détectez toutes les erreurs dont vous pouvez récupérer de manière significative.Parfois, c'est tout.

D'après mon expérience, c'est plus important l'exception provient de laquelle l'exception est réellement levée.Si vous conservez vos exceptions dans des espaces restreints, vous n'avalerez généralement rien qui serait autrement utile.La plupart des informations codées dans le type d'erreur sont des informations auxiliaires, vous finissez donc généralement par détecter efficacement tous de toute façon (mais vous devez maintenant consulter la documentation de l'API pour obtenir l'ensemble total des exceptions possibles).

Gardez à l'esprit que certaines exceptions qui devraient remonter au sommet dans presque tous les cas, comme celle de Python KeyboardInterrupt et SystemExit.Heureusement pour Python, celles-ci sont conservées dans une branche distincte de la hiérarchie des exceptions, vous pouvez donc les laisser bouillonner en attrapant Exception.Une hiérarchie d'exceptions bien conçue rend ce genre de chose vraiment simple.

Le principal moment où la détection d'exceptions générales causera de sérieux problèmes est lorsqu'il s'agit de ressources qui doivent être nettoyées (peut-être dans un finally clause), puisqu'un gestionnaire fourre-tout peut facilement manquer ce genre de chose.Heureusement, ce n'est pas vraiment un problème pour les langues avec defer, construit comme celui de Python with, ou RAII en C++ et Rust.

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