Question

J'ai eu affaire à des cas où je jetterais / réémettre une exception en sachant que le code qui l'entoure attraperait l'exception spécifique. Mais est-il du temps que vous voulez lancer une exception, sachant qu'il ne serait pas pris?

Ou du moins, pas attraper une exception?

Exceptions arrêtent immédiatement la demande à moins que leur droit traitées? Donc je suppose que je vous demande si vous voulez jamais laisser volontairement mourir votre application?

Était-ce utile?

La solution

Si votre application va principalement être utilisé par d'autres clients et ne sont pas autonomes, il est généralement judicieux de lancer des exceptions si une condition pose que vous ne savez pas comment (ou ne voulez pas) gérer et il n'y a aucun moyen raisonnable pour que vous puissiez le récupérer. Les clients doivent être en mesure de décider comment ils veulent gérer toutes les exceptions que vous pourriez jeter.

Par contre, si votre application est le point final, lancer une exception devient essentiellement un mécanisme de notification pour alerter les gens que quelque chose a terriblement mal tourné. Dans ce cas, vous devez considérer quelques petites choses:

  • Quelle est l'importance du fonctionnement continu de l'application? Est-ce vraiment une erreur irrécupérable? Lancer une exception et la résiliation de votre programme n'est pas quelque chose que vous voulez faire sur la navette spatiale.

  • Utilisez-vous des exceptions comme proxy pour l'enregistrement réel Il n'y a presque jamais une raison de le faire?; envisager un véritable mécanisme de journalisation à la place. Intercepter l'exception et ont l'enregistreur fonctionne ce qui est arrivé.

  • Qu'est-ce que vous essayez de transmettre en lançant l'exception vous? Demandez-vous ce que la valeur à lancer une nouvelle exception, et d'examiner avec soin s'il n'y a pas une meilleure façon de faire ce que vous voulez.

  • Non attrapant une exception peut laisser des ressources dans un mauvais état. Si vous ne quittez pas avec élégance, les choses ne sont généralement pas nettoyés pour vous. Assurez-vous que vous comprenez ce que vous faites si vous avez besoin de le faire -. Et si vous n'allez pas attraper, considérer au moins un bloc de sorte que vous pouvez try-finally faire un peu de rangement

Autres conseils

Il y a une très bonne règle que je suis tombé il y a un certain temps:

Lancer une exception lorsqu'une méthode ne peut pas faire ce que son nom dit qu'il fait.

L'idée est qu'une exception indique que quelque chose a mal tourné. Lorsque vous implémentez une méthode, il est de votre responsabilité de savoir si elle sera utilisée correctement ou non. Que ce soit le code à l'aide de votre méthode attire l'exception ou non pas votre responsabilité, mais la responsabilité de la personne qui utilise votre méthode.

Une autre règle à suivre est:

Ne pas attraper une exception à moins que vous savez ce que vous voulez faire.

De toute évidence, vous devez inclure le code de nettoyage dans un bloc try ... finally, mais vous ne devriez jamais attraper juste une exception juste pour le plaisir de l'attraper. Et vous ne devriez jamais avaler des exceptions en silence. Bien qu'il y ait des occasions où vous voudrez peut-être attraper toutes les exceptions (par exemple en faisant catch (Exception ex) en C #), ceux-ci sont assez rares et ont généralement une raison technique très spécifique. Par exemple, lorsque vous utilisez des fils dans .NET 2.0 ou version ultérieure, si une exception échappe à votre fil, il fera l'ensemble du domaine d'application pour décharger. Dans ces cas, cependant, à tout le moins, vous devez enregistrer les détails d'exception comme une erreur et fournir une explication dans les commentaires.

En général, et certainement dans les premières itérations de votre application, ne pas attraper l'exception. Plus souvent qu'autrement, la reprise d'une exception, il faudra une règle d'affaires de quelque sorte, et, plus souvent qu'autrement, ces règles d'affaires ne sont pas définies pour vous. Si vous « gérer » l'exception au lieu de laisser l'application mourir alors vous serez très probablement inventer des règles métier pour votre client. Pas bon.

Le schéma général d'attraper toutes les exceptions juste pour le plaisir de l'attraper m'a causé plus de maux de tête que je peux compter. Il arrive souvent que quelqu'un met une sorte de code de gestion des exceptions dans l'application générique, qui finit inévitablement par se cacher un bug ou la création d'un comportement qui est indésirable. (Soit dit en passant, la capture et non rethrowing est encore pire.)

Alors, je vous suggère de demander à la place: "? Quand dois-je attraper une exception"

Bien sûr. Par exemple, si vous essayez de charger des octets dans une chaîne en Java:

try {
  String myString = new String(byteArray, "UTF-8");
} catch (UnsupportedEncodingException e) {
  // Platform doesn't support UTF-8?  What is this, 1991?
  throw new RuntimeExceptione(e);
}

Dans ce cas, il n'y a pas de dégradation gracieuse, la plate-forme peut tout simplement pas supporter l'opération désirée. Vous pouvez vérifier cette condition lors de l'initialisation tout ce que vous voulez, mais le constructeur de chaîne jette encore cette exception, et vous devez faire face. Ou alors, utiliser Charset.forName ():)

Voici la chose ... il est sur le point « couches », ou « encapsulation », ou « couplage faible ». À un certain endroit dans votre base de code, vous écrivez une méthode pour faire quelque chose. Dire que c'est une méthode publique. Par conséquent, il ne devrait pas prendre beaucoup ou quoi que ce soit au sujet de l'appelant ... plutôt, il devrait simplement faire le travail qu'il est censé faire, quel que soit la personne qui appelle et quel contexte l'appelant est dans.

Et si, pour une raison quelconque, il ne peut pas terminer son travail, il a besoin de dire l'appelant « Désolé, je ne pouvais pas le faire, et voici pourquoi. » Les exceptions sont un excellent mécanisme pour le laisser dire que l'appelant (et non le seul mécanisme, mais le meilleur mécanisme que j'ai jamais vu pour la plupart des cas).

Alors, quand vous jetez l'exception, vous ne savez pas si elle sera prise ou non ... parce que vous êtes exposant une méthode publique et vous avez aucune idée de qui pourrait choisir de l'appeler et pourquoi.

La capture de l'exception est le travail du « contexte ». Par exemple, supposons que vous écrivez une bibliothèque avec des méthodes publiques qui pourraient lancer des exceptions. Alors, dites que vous utilisez cette bibliothèque à partir d'une application Windows Forms. Windows Forms application peut intercepter les exceptions et afficher une boîte de message à l'utilisateur.

Mais plus tard, vous pouvez utiliser la même bibliothèque à partir d'un service Windows. Le service serait plus susceptible d'attraper l'exception, connectez-elle, renvoie une erreur à l'appelant original, mais continuer à courir pour qu'il puisse traiter de nouvelles demandes.

Ainsi, l'exception est comme un accord contractuel entre l'appelant et le fournisseur. Le fournisseur dit: « Je vais soit faire le travail ou vous dire pourquoi je ne peux pas. Ce que vous faites à partir de là est votre propre entreprise. » Et l'appelant dit: « OK, si vous ne pouvez pas faire le travail, juste me dire pourquoi, et je déciderai quoi faire dans ce cas. »

  

Mais est-il du temps que vous voulez lancer une exception, sachant qu'il ne serait pas pris?

Je dirais que si vous jetez manuellement une exception, la plupart du temps vous ne savez pas si ce sera pris. Si vous saviez que ce serait vous pourriez juste attrapé gérer vous-même plutôt que de jeter l'exception en premier lieu.

Pour être juste, je suppose que cela dépend en partie du type de programmation que vous faites, et parfois même programmeur finit par construire la bibliothèque et le code qui consume ladite banque.

  

Voulez-vous jamais attraper pas une exception?

Si vous ne vous attendiez pas / ne connaissaient pas une exception pourrait être levée. Mais mettre cela de côté et en supposant que vous êtes au courant de l'exception, parfois, vous savez à ce sujet à un niveau, mais connaissez le niveau supérieur suivant est l'endroit plus approprié pour y faire face.

Cela dépend du type d'application. Les applications Web peuvent continuer à fonctionner même après des exceptions ont barboter jusqu'à contexte d'exécution.

Il est pratique courante de « lancer / rethrow » une exception si vous attrapez l'exception à un niveau où il ne peut pas être traitée. Mais, vous presque toujours ajouter du contexte à la question, à tout le moins ajouter une journalisation au plus haut niveau pour dire qu'il a été pris et relancée.

par exemple

A appelle B appelle C (jette exception)

B prises / rethrows

A prises.

Dans ce cas, vous voulez B pour ajouter un peu de journalisation afin que vous puissiez différencier entre génération B et lancer une erreur, et la génération C et lancer une erreur. Cela vous permettra une plus grande capacité de déboguer et résoudre les problèmes plus tard.

En général, vous voulez presque jamais une exception pour tuer votre programme. La meilleure pratique est d'attraper l'exception et sortir gracieusement. Cela vous permet d'enregistrer toutes les informations actuellement et libérer des ressources qui sont utilisées afin qu'ils ne deviennent pas corrompus. Si vous avez l'intention de sortir, vous pouvez créer votre propre rapport d'information « noyau dump » qui comprend les choses que vous faisiez lorsque vous avez pris l'exception fatale.

Si vous laissez l'exception tuer votre processus, vous éliminez votre chance d'obtenir des informations personnalisées sur mesure accident, et vous sautez aussi la partie où vous fournir à l'utilisateur un message d'erreur convivial puis sortie.

Alors, je recommande toujours attraper des exceptions, et ne jamais les laisser volontairement se déchaînent dans votre programme.

EDIT

Si vous écrivez une bibliothèque, vous devez choisir à l'avance si votre fonction lancer une exception, ou avoir une exception en toute sécurité. Dans ces cas, parfois, vous jetterez une exception et ne savent pas si le demandeur va l'attraper. Mais dans ce cas, l'attraper est pas votre responsabilité, tant que l'api déclare que la fonction pourrait lancer des exceptions. (Je cherche un mot qui signifie « pourrait peut-être exception throw » ... quelqu'un sait ce qu'il est? Ça va bug moi toute la journée.)

Tout d'abord, il y a absolument des situations où il est préférable de ne pas attraper une exception.

Parfois, une exception peut parfois vous dire que votre programme est dans un état inconnu. Il y a un certain nombre d'exceptions lorsque cela est à peu près intrinsèquement vrai étant donné le type d'exception. Un vous dit essentiellement NullReferenceException « il y a un bug ». Et en attrapant une telle exception, vous pouvez masquer le bug, qui sonne bien à court terme, mais à long terme, vous seriez plus heureux de le réparer. Le produit ne peut pas tomber en panne, mais il ne sera certainement pas le comportement attendu.

Mais cela est également vrai pour les types d'exception que nous inventons pour nous-mêmes. Parfois, le fait que exception A a été jeté devrait être « impossible » -. Et pourtant il est arrivé, donc il y a un bug

En outre, il arrive quelque chose très important quand vous attrapez une exception: les blocs pour la finally toute la pile d'appels à l'intérieur du bloc try (et tout ce qu'elle appelle) seront exécutés. Qu'est-ce que ces blocs enfin faire? Eh bien, quoi que ce soit. Et si le programme est dans un état inconnu, je ne signifie vraiment quoi que ce soit . Ils pourraient effacer les données des clients de valeur à partir du disque. Ils pourraient jeter plus d'exceptions. Ils pourraient corrompre les données en mémoire, ce qui rend le virus impossible à diagnostiquer.

Alors, quand une exception indique un état inconnu, vous ne voulez pas courir plus de code, alors quoi que vous fassiez, ne pas attraper l'exception . Laissez voler passé, et votre programme prendra fin sans dommage, et Windows Error Reporting sera en mesure de saisir l'état du programme tel qu'il était quand a été détecté le problème. Si vous attrapez l'exception, vous causer plus de code à exécuter, qui bousiller encore l'état du programme.

En second lieu, si vous jetez une exception en sachant qu'il ne sera pas pris? Je pense que cette question se méprend sur la nature des méthodes réutilisables. L'idée d'une méthode est qu'il a un « contrat » qu'il suit: il accepte certains paramètres et renvoie une certaine valeur, plus aussi jette certaines exceptions dans certaines conditions. C'est le contrat - il est à l'appelant ce qu'ils font. Pour certains appelants, sauf A pourrait indiquer une condition récupérable. Pour les autres appelants, il peut indiquer un bogue. Et d'après ce que je l'ai dit ci-dessus, il devrait être clair que si une exception indique un bug, il ne doit pas être pris .

Et si vous vous demandez ce que cela signifie pour le Exception Microsoft Enterprise Library Bloquer la manipulation : oui, il est assez cassé. Ils vous disent de et de décider ensuite catch (Exception x) si vous souhaitez réémettre en fonction de votre politique; trop tard - les blocs ont déjà <=> exécuté par ce point. Ne pas le faire.

Vous ne voudriez probablement pas une exception non interceptée partout où les utilisateurs finaux peuvent le voir, mais il est souvent acceptable pour permettre aux clients de votre API (autres programmeurs) décider comment gérer les exceptions.

Par exemple, supposons que vous concevez une bibliothèque de classes Java. Vous exposer une méthode publique qui prend dans une chaîne. Dans votre application, une valeur d'entrée nulle provoquerait une erreur. Au lieu de gérer l'erreur vous-même, il serait acceptable de vérifier une valeur nulle, puis jeter un IllegalArgumentException.

Vous devez, bien sûr, un document que votre méthode renvoie cette exception dans ce cas. Ce comportement fait partie du contrat de votre méthode.

Cela dépend de ce que vous entendez par « être pris ». Quelque chose, quelque part attire finalement l'exception que ce soit le système d'exploitation sous-jacent ou autre chose.

Nous avons un système de workflow qui exécute les plans de travail comprenant des emplois individuels. Chaque tâche exécute une unité de code. Pour certaines des exceptions, nous ne voulons pas les traiter dans le code, mais jeter la pile de sorte que le système de workflow externe attrape (ce qui arrive complètement à l'extérieur du processus du lanceur).

Si vous écrivez toute l'application, vos raisons sont vos propres. Je peux penser à quelques situations où vous peut veulent jeter l'exception et de laisser mourir l'application, la plupart d'entre eux ne sont pas très bonnes raisons cependant.

La meilleure raison est généralement lors du débogage. Désactiver fréquemment des exceptions pendant le débogage pour me permettre de savoir mieux où quelque chose est un échec. Vous pouvez aussi activer les pauses d'exception jetés dans le débogueur si vous utilisez sur une machine avec le débogueur.

Une autre raison possible est lors de la poursuite après une exception est levée n'a pas de sens ou entraînerait une possible corruption des données irrécupérables ou pire (pensez robots avec des faisceaux laser, mais vous devriez être sacrément sûr que vos offres de applicaiton avec ces situations OMI , écraser le programme est juste la façon paresseuse).

Si vous écrivez du code API, ou un code-cadre que vous ne vous utilisez, vous ne savez pas si quelqu'un va attraper vos exceptions.

Eh oui, il est ma seule occasion de frapper le développeur consommer le service / objet pour leur dire « Ur dO1n mal !!!! ».

Ce et se débarrasser des possibilités que vous ne voulez pas autoriser ou sont apparemment « impossible ». Apps qui attrapent toutes les exceptions et continue sont juste un jardin clos entouré par le chaos.

Si je besoin d'un système modérément important qui est en train de traiter les données en quelque sorte dans ce que je crois être une manière cohérente.

Quelque part le long de la ligne, je perçois que l'état de l'application est devenue incompatible.

Le système ne sait pas (encore) comment corriger l'incohérence et grâce à récupérer

Alors, oui, je jetterais une exception avec autant de détails que possible et provoquer l'application de mourir le plus rapidement possible, afin d'éviter ainsi limiter les dommages aux données. Si elle peut être récupérée, il serait important de ne pas aggraver le problème en essayant mollement pour couvrir les dégâts.

Plus tard le long de la ligne, une fois la chaîne d'événements qui a conduit à l'incohérence est mieux comprise, je peux tendance plus attraper cette exception, réparer l'état, et continuer avec un minimum d'interruption.

Une bibliothèque sera souvent jeter des exceptions fondées sur des contrôles de programmation défensive, une condition doit se produire qui ne devrait pas avoir été autorisés à se présenter par le code d'application. Applications code sera souvent écrit de telle sorte que la plupart de ces conditions invalides ne se posera jamais, et par conséquent les exceptions ne sera jamais jeté, donc il n'y a pas de point les attraper.

En fonction de la langue (je pense surtout en termes de C ++ plutôt que C #, et pas clairement quelles sont les différences) l'effet d'une exception non effectivement jeté est probablement la même chose que ce qui était à faire dans le jours avant exceptions ont été inventées. Une politique commune pour la programmation défensive dans les bibliothèques C, par exemple, était de mettre fin immédiatement le programme avec un message d'erreur.

La différence est que si le jet d'exception ne se révéler possible (nous espérons que cela sera découvert par les tests unitaires), il est relativement facile d'ajouter un gestionnaire d'exception qui peut récupérer le problème d'une manière plus constructive. Vous n'avez pas à réécrire la bibliothèque, ou ajouter des contrôles complexes dans le code d'application pour assurer la condition ne peut se produire avant l'appel exception-lancement est fait.

J'ai tout à fait quelques exception jette qui ne sont jamais pris. Ils sont tous à des fins défensives, et tout en étant uncaught est mauvais pour une exception qui ne se produit, cela arrive que jamais au cours du développement et de tests, pour des conditions d'erreur, j'omis de tenir compte dans le code d'application jusqu'à présent. Et quand il arrive, il est rare que le correctif soit maladroit - pas besoin d'une grande échelle refactoring, pas besoin du code des applications pour être massivement compliquée avec des contrôles de l'état d'erreur, juste une clause de capture avec une reprise relativement simple ou " Je suis désolé, Dave, je crains que je ne peux pas le faire « . sans manquer à l'application entière.

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