Rédigez-vous des exceptions pour des problèmes spécifiques ou des exceptions générales ?

StackOverflow https://stackoverflow.com/questions/21652

  •  09-06-2019
  •  | 
  •  

Question

J'ai du code qui donne un identifiant utilisateur à un utilitaire qui envoie ensuite un e-mail à cet utilisateur.

emailUtil.sendEmail(userId, "foo");

public void sendEmail(String userId, String message) throws MailException {
    /* ... logic that could throw a MailException */
}

MailException pourrait être lancé pour un certain nombre de raisons, des problèmes avec l'adresse e-mail, des problèmes avec le modèle de courrier, etc.

Ma question est la suivante :créez-vous un nouveau type d'exception pour chacune de ces exceptions, puis traitez-les individuellement ou créez-vous une MailException et stockez-vous ensuite quelque chose dans l'exception (quelque chose de lisible par ordinateur, pas le texte de description) qui nous permet de faire différentes choses basé sur ce qui s'est réellement passé.

Modifier: À titre de précision, les exceptions ne concernent pas les journaux et ainsi de suite, cela concerne la façon dont le code y réagit.Pour continuer avec l'exemple du courrier, disons que lorsque nous envoyons du courrier, cela peut échouer parce que vous n'avez pas d'adresse e-mail, ou parce que vous n'avez pas d'adresse e-mail. valide adresse e-mail, ou cela pourrait échouer.etc.

Mon code voudrait réagir différemment à chacun de ces problèmes (principalement en modifiant le message renvoyé au client, mais également la logique réelle).

Serait-il préférable d'avoir une implémentation d'exception pour chacun de ces problèmes ou une exception générale contenant quelque chose de interne (une énumération par exemple) qui permet au code de distinguer de quel type de problème il s'agit.

Était-ce utile?

La solution

Je commence généralement par une exception générale et je la sous-classe si nécessaire.Je peux toujours intercepter l'exception générale (et avec elle toutes les exceptions sous-classées) si nécessaire, mais aussi l'exception spécifique.

Un exemple de l'API Java est IOException, qui a des sous-classes comme FileNotFoundException ou EOFException (et bien plus encore).

De cette façon, vous bénéficiez des avantages des deux, vous n'avez pas de clauses de renvoi telles que :

throws SpecificException1, SpecificException2, SpecificException3 ...

un général

throws GeneralException

est assez.Mais si vous souhaitez réagir de manière particulière à des circonstances particulières, vous pouvez toujours détecter l'exception spécifique.

Autres conseils

Dans mon code, je trouve que la PLUPART des exceptions s'infiltrent jusqu'à une couche d'interface utilisateur où elles sont interceptées par mes gestionnaires d'exceptions qui affichent simplement un message à l'utilisateur (et écrivent dans le journal).Après tout, c'est une exception inattendue.

Parfois, je souhaite intercepter une exception spécifique (comme vous semblez vouloir le faire).Cependant, vous constaterez probablement que cela est quelque peu rare et que cela indique l'utilisation d'exceptions pour contrôler la logique - ce qui est inefficace (lent) et souvent mal vu.

Donc, en utilisant votre exemple, si vous souhaitez exécuter une logique spéciale lorsque le serveur de messagerie n'est pas configuré, vous souhaiterez peut-être ajouter une méthode à l'objet emailUtil comme :

public bool isEmailConfigured()

...appelez cela en premier, au lieu de rechercher une exception spécifique.

Lorsqu'une exception se produit, cela signifie en réalité que la situation était complètement inattendue et que le code ne peut pas la gérer. Le mieux que vous puissiez faire est donc de la signaler à l'utilisateur (ou de l'écrire dans un journal ou de redémarrer).

Quant à avoir une hiérarchie d'exceptions par rapport aux exceptions contenant des codes d'erreur, je fais généralement cette dernière.Il est plus facile d'ajouter de nouvelles exceptions si vous avez simplement besoin de définir une nouvelle constante d'erreur au lieu d'une toute nouvelle classe.Mais cela n’a pas beaucoup d’importance tant que vous essayez d’être cohérent tout au long de votre projet.

@Chris.Lively

Vous savez que vous pouvez passer un message dans votre exception, voire les "codes de statut".Vous réinventez la roue ici.

J'ai découvert que si vous avez besoin que CODE décide quoi faire en fonction de l'exception renvoyée, créez une exception bien nommée sous-classant un type de base commun.Le message transmis doit être considéré comme « uniquement des yeux humains » et trop fragile pour qu’il soit possible de prendre des décisions.Laissez le compilateur faire le travail !

Si vous devez transmettre cela à une couche supérieure via un mécanisme qui ne prend pas en compte les exceptions vérifiées, vous pouvez l'envelopper dans une sous-classe nommée appropriée de RuntimeException (MailDomainException) qui peut être rattrapée et la cause d'origine peut être prise en compte.

Cela dépend de ce que fait votre application.Vous souhaiterez peut-être lancer des exceptions individuelles dans des cas tels que

  • L'application est en haute disponibilité
  • L'envoi d'e-mails est particulièrement important
  • La portée de l'application est petite et l'envoi d'e-mails en représente une grande partie
  • L'application sera déployée sur un site distant et vous n'obtiendrez que des journaux pour le débogage
  • Vous pouvez récupérer un sous-ensemble d'exceptions encapsulées dans mailException mais pas d'autres

Dans la plupart des cas, je dirais simplement d'enregistrer le texte de l'exception et de ne pas perdre votre temps à granulariser des exceptions déjà assez granulaires.

Je pense qu'une combinaison de ce qui précède vous donnera le meilleur résultat.

Vous pouvez lancer différentes exceptions en fonction du problème.par exemple.Adresse e-mail manquante = ArgumentException.

Mais ensuite, dans la couche UI, vous pouvez vérifier le type d'exception et, si nécessaire, le message, puis afficher un message approprié à l'utilisateur.Personnellement, j'ai tendance à afficher un message d'information à l'utilisateur uniquement si un certain type d'exception est émis (UserException dans mon application).Bien sûr, vous devez nettoyer et vérifier les entrées de l'utilisateur autant que possible plus haut dans la pile pour vous assurer que toutes les exceptions sont générées par des scénarios vraiment improbables, et non comme un filtre pour les e-mails mal formés qui peuvent facilement être vérifiés avec une regex.

Je ne m'inquiéterais pas non plus des implications en termes de performances liées à la détection d'une exception provenant d'une entrée utilisateur.La seule fois où vous constaterez des problèmes de performances dus aux exceptions, c'est lorsqu'elles sont lancées et prises dans une boucle ou similaire.

Au lieu d'utiliser des exceptions, j'ai tendance à renvoyer une liste d'objets d'état provenant de méthodes qui peuvent avoir des problèmes d'exécution.Les objets d'état contiennent une énumération de gravité (information, avertissement, erreur, ...), un nom d'objet d'état comme "Adresse e-mail" et un message lisible par l'utilisateur comme "Adresse e-mail mal formatée".

Le code appelant déciderait alors lequel filtrer jusqu’à l’interface utilisateur et lequel gérer lui-même.

Personnellement, je pense que les exceptions sont strictement réservées aux cas où vous ne pouvez pas implémenter une solution de code normale.Les performances et les restrictions de manipulation sont tout simplement un peu trop lourdes pour moi.

Une autre raison d'utiliser une liste d'objets d'état est que l'identification de plusieurs erreurs (comme lors de la validation) est BEAUCOUP plus facile.Après tout, vous ne pouvez lancer qu’une seule exception qui doit être gérée avant de continuer.

Imaginez un utilisateur soumettant un e-mail contenant une adresse de destination mal formée et contenant un langage que vous bloquez.Lancez-vous l'exception de courrier électronique mal formée, puis, après avoir corrigé le problème et soumis à nouveau, lancez-vous une exception de langage incorrect ?Du point de vue de l’expérience utilisateur, les traiter tous en même temps est une meilleure façon de procéder.

MISE À JOUR: combiner les réponses

@Jonathan :Ce que je voulais dire, c'est que je peux évaluer l'action, dans ce cas en envoyant un e-mail, et renvoyer plusieurs raisons d'échec.Par exemple, « mauvaise adresse e-mail », « titre du message vide », etc.

À une exception près, vous êtes limité à simplement percoler un problème, puis à demander à l'utilisateur de soumettre à nouveau, auquel cas il découvre un deuxième problème.C'est une très mauvaise conception de l'interface utilisateur.

Réinventer la roue..peut-être.Cependant, la plupart des applications doivent analyser l'ensemble de la transaction afin de donner la meilleure information possible à l'utilisateur.Imaginez si votre compilateur s'arrêtait net à la première erreur.Vous corrigez ensuite l'erreur et appuyez à nouveau sur la compilation pour qu'elle s'arrête à nouveau pour une erreur différente.Quelle douleur dans les fesses.Pour moi, c'est exactement le problème du lancement d'exceptions et donc la raison pour laquelle j'ai dit d'utiliser un mécanisme différent.

J'ai tendance à avoir moins de types d'exceptions, même si ce n'est pas vraiment la façon OO de le faire.Au lieu de cela, j'ai mis une énumération à mes exceptions personnalisées, qui classe l'exception.La plupart du temps, j'ai une exception de base personnalisée, qui conserve quelques membres, qui peuvent être remplacées ou personnalisées dans des types d'exception dérivés.

Il y a quelques mois, j'ai blogué sur l'idée de comment internationaliser les exceptions.Il comprend certaines des idées mentionnées ci-dessus.

Bien que vous puissiez différencier l'exécution du code en regardant l'exception, peu importe si cela est fait par le "mode hiérarchique catch exceptionType" ou par "if(...) else...mode code d'exception"

mais si vous développez un logiciel qui va être utilisé par d'autres personnes, comme une bibliothèque, je pense qu'il est utile de créer vos propres types d'exceptions pour remarquer aux autres personnes que votre logiciel peut lancer d'autres exceptions que les exceptions normales, et qu'elles feraient mieux de détecter et les résoudre.

Lorsque j'utilise une bibliothèque et que ses méthodes lancent simplement une « exception », je me demande toujours :Qu'est-ce qui peut provoquer cette exception ?, comment mon programme doit-il réagir ?, s'il y a un javadoc, la cause sera peut-être expliquée, mais la plupart du temps, il n'y a pas de javadoc ou l'exception n'est pas expliquée.Trop de frais généraux peuvent être évités avec un WellChossenExceptionTypeName

Cela dépend si le code qui intercepte l'exception doit faire la différence entre les exceptions ou si vous utilisez simplement des exceptions pour échouer vers une page d'erreur.Si vous devez faire la différence entre une exception NullReference et votre MailException personnalisée plus haut dans la pile d'appels, prenez le temps de l'écrire.Mais la plupart du temps, les programmeurs utilisent simplement les exceptions comme fourre-tout pour générer une erreur sur la page Web.Dans ce cas, vous gaspillez simplement vos efforts à écrire une nouvelle exception.

je passerais juste par là

throw new exception("WhatCausedIt")

si vous souhaitez gérer vos exceptions, vous pouvez transmettre un code au lieu de "WhatCausedIt", puis réagir aux différentes réponses avec une instruction switch.

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