J'ai lu le code d'un collègue et j'ai constaté qu'il attrapait souvent diverses exceptions et lançait toujours une "RuntimeException" à la place. J'ai toujours pensé que c'était une très mauvaise pratique. Ai-je tort?
java
exceptions
exception-handling
RoflcoptrException
la source
la source
Function
-à- d .Predicate
, Etc. ) ne comportent pas de clause de projection paramétrée. Cela signifie que vous devez capturer, encapsuler et redistribuer les exceptions vérifiées dans la boucle interne de toutes les méthodes stream (). Cela en soi fait pencher la balance pour moi pour savoir si les exceptions vérifiées sont une mauvaise idée.Réponses:
Je ne connais pas suffisamment le contexte pour savoir si votre collègue fait quelque chose de mal ou pas, alors je vais en discuter de manière générale.
Je ne pense pas qu'il soit toujours incorrect de transformer les exceptions vérifiées en une sorte d'exception d'exécution . Les exceptions vérifiées sont souvent mal utilisées et abusées par les développeurs.
Il est très facile d'utiliser des exceptions vérifiées lorsqu'elles ne sont pas censées être utilisées (conditions irrécupérables, voire contrôle du flux). Surtout si une exception vérifiée est utilisée pour des conditions dans lesquelles l'appelant ne peut pas récupérer, je pense qu'il est justifié de transformer cette exception en une exception d'exécution avec un message / état utile. Malheureusement, dans de nombreux cas, lorsque l’on est confronté à une condition irrécupérable, on a tendance à avoir un bloc vide, ce qui est l’une des pires choses que vous puissiez faire. Déboguer un tel problème est l’un des plus gros problèmes qu’un développeur puisse rencontrer.
Donc, si vous pensez que vous avez affaire à une condition récupérable, vous devez la gérer en conséquence et l'exception ne doit pas être transformée en une exception d'exécution. Si une exception vérifiée est utilisée pour des conditions irrécupérables, il est justifié de la transformer en une exception d'exécution .
la source
Cela peut être bon . Lisez s'il vous plaît:
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
Lancer des exceptions vérifiées et ne pas être capable de s'en remettre ne sert à rien.
Certaines personnes pensent même que les exceptions vérifiées ne devraient pas être utilisées du tout. Voir http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html.
Également du même lien:
la source
Non, tu n'as pas tort. Sa pratique est extrêmement erronée. Vous devriez lancer une exception qui capture le problème qui l’a provoquée. RunTimeException est large et va trop loin. Il devrait s'agir d'une exception NullPointerException, ArgumentException, etc. Ce qui décrit avec précision ce qui s'est mal passé. Cela permet de différencier les problèmes que vous devez gérer et de laisser le programme survivre par rapport aux erreurs qui devraient constituer un scénario "Ne réussissez pas". Ce qu’il fait n’est que légèrement meilleur que "On Error Resume Next" sauf s’il manque quelque chose dans les informations fournies dans la question.
la source
Ça dépend.
Cette pratique peut même être sage . Il existe de nombreuses situations (par exemple dans le développement Web), dans lesquelles, si une exception se produit, vous ne pouvez rien faire (car vous ne pouvez pas par exemple réparer une base de données incohérente à partir de votre code :-), seul un développeur peut le faire). Dans ces situations, il est sage d'encapsuler l'exception levée dans une exception d'exécution et de la renvoyer. Ensuite, vous pouvez intercepter toutes ces exceptions dans une couche de traitement des exceptions, consigner l’erreur et afficher à l’utilisateur un code d'erreur + un message bien localisé.
D'autre part , si l'exception n'est pas à l'exécution (est cochée), le développeur de l'API indique que cette exception est résolvable et doit être réparée. Si c'est possible, vous devriez absolument le faire.
L’autre solution pourrait être de rétablir cette exception vérifiée dans le calque appelant, mais si vous ne parvenez pas à la résoudre, où l’exception s’est produite, vous ne pourrez probablement pas la résoudre ici également ...
la source
exception handling layer
- par exemple dans une application Web, un filtre.J'aimerais avoir des commentaires à ce sujet, mais je trouve qu'il y a des moments où ce n'est pas nécessairement une mauvaise pratique. (Ou terriblement mauvais). Mais peut-être que je me trompe.
Souvent, une API que vous utilisez générera une exception que vous ne pouvez pas imaginer être réellement lancée dans votre cas d'utilisation spécifique. Dans ce cas, il semble parfaitement correct de lancer une exception RuntimeException avec l’exception interceptée comme cause. Si cette exception est levée, cela sera probablement la cause d'une erreur de programmation et ne se situe pas entre les limites d'une spécification correcte.
En supposant que l'exception RuntimeException ne soit pas interceptée et ignorée plus tard, ce n'est pas proche d'un OnErrorResumeNext.
OnErrorResumeNext se produirait quand quelqu'un attraperait une exception et l'ignorerait simplement ou l'imprimerait simplement. C'est une pratique terriblement mauvaise dans presque tous les cas.
la source
TL; DR
Prémisse
Conclusion
Nous pouvons réexaminer une exception vérifiée en tant qu'exception d'exécution si le code de propagation ou d'interface suppose que l'implémentation sous-jacente dépend d'un état externe, alors que ce n'est clairement pas le cas.
Cette section aborde le sujet du moment où l’une des exceptions doit être levée. Vous pouvez passer à la barre horizontale suivante si vous souhaitez simplement lire une explication plus détaillée de la conclusion.
Quand est-il approprié de lancer une exception d'exécution? Vous lève une exception d'exécution lorsqu'il est clair que le code est incorrect et que la récupération est appropriée en modifiant le code.
Par exemple, il est approprié de lancer une exception d'exécution pour les éléments suivants:
Cela lève une exception d'exécution division par zéro. Ceci est approprié car le code est défectueux.
Ou par exemple, voici une partie du
HashMap
constructeur de 's:Afin de fixer la capacité initiale ou le facteur de charge, il convient que vous modifiiez le code pour vous assurer que les valeurs correctes sont bien transmises. Cela ne dépend pas de la disponibilité d’un serveur distant, de l’état actuel du disque, un fichier ou un autre programme. Ce constructeur appelé avec des arguments non valides dépend de l'exactitude du code appelant, qu'il s'agisse d'un calcul erroné ayant conduit aux paramètres non valides ou d'un flux inapproprié manquant une erreur.
Quand est-il approprié de lancer une exception cochée? Vous lève une exception cochée lorsque le problème est récupérable sans changer le code. Ou, pour le dire autrement, vous lâchez une exception vérifiée lorsque l'erreur est liée à l'état alors que le code est correct.
Maintenant, le mot "récupérer" peut être délicat ici. Cela peut signifier que vous trouvez un autre moyen d'atteindre l'objectif: par exemple, si le serveur ne répond pas, vous devriez essayer le serveur suivant. Si ce type de récupération est possible pour votre cas, c'est bien, mais ce n'est pas la seule chose que signifie récupération - la récupération peut simplement afficher une boîte de dialogue d'erreur indiquant à l'utilisateur ce qui s'est passé, ou bien s'il s'agit d'une application serveur, alors envoyer un courrier électronique à l'administrateur, ou même simplement consigner l'erreur de manière appropriée et concise.
Prenons l'exemple cité dans la réponse de mrmuggles:
Ce n'est pas la bonne façon de gérer l'exception vérifiée. La simple incapacité à gérer l'exception dans le champ d'application de cette méthode ne signifie pas que l'application doit être plantée. Au lieu de cela, il convient de le propager à une portée plus élevée comme ceci:
Ce qui permet la possibilité de récupération par l'appelant:
Les exceptions cochées sont un outil d'analyse statique, elles indiquent clairement à un programmeur ce qui pourrait mal tourner lors d'un appel donné sans lui demander d'apprendre la mise en oeuvre ou de passer par un processus d'essais et d'erreurs. Cela permet de s'assurer facilement qu'aucune partie du flux d'erreur ne sera ignorée. Le fait de renvoyer une exception vérifiée en tant qu'exception d'exécution va à l'encontre de cette fonctionnalité d'analyse statique qui économise du travail.
Il est également intéressant de mentionner que la couche appelante a un meilleur contexte du plus grand schéma des choses, comme cela a été démontré ci-dessus. Il pourrait y avoir plusieurs causes à
dataAccessCode
l'appel, la raison spécifique de l'appel n'étant visible que par l'appelant - il est donc en mesure de prendre une meilleure décision lors de la récupération correcte en cas d'échec.Maintenant que cette distinction est claire, nous pouvons en déduire le moment opportun pour réexaminer une exception vérifiée en tant qu’exception d’exécution.
Compte tenu de ce qui précède, à quel moment convient-il de rétablir une exception vérifiée en tant qu'exception RuntimeException? Lorsque le code que vous utilisez suppose une dépendance à un état externe, mais vous pouvez clairement affirmer qu'il ne dépend pas d'un état externe.
Considérer ce qui suit:
Dans cet exemple, le code se propage
IOException
car l'API deReader
est conçue pour accéder à un état externe. Cependant, nous savons que laStringReader
mise en œuvre n'accède pas à un état externe. À ce niveau, où nous pouvons certainement affirmer que les parties impliquées dans l’appel n’ont pas accès à IO ou à tout autre état externe, nous pouvons sans risque rediffuser l’exception comme une exception d’exécution, sans surprendre des collègues qui ne sont pas au courant de notre implémentation (et sont éventuellement en supposant que le code d'accès IO jettera unIOException
).La raison pour garder strictement vérifiées les exceptions dépendantes de l'état externe est qu'elles ne sont pas déterministes (contrairement aux exceptions dépendantes de la logique, qui seront reproduites de manière prévisible pour une version du code). Par exemple, si vous essayez de diviser par 0, vous obtiendrez toujours une exception. Si vous ne divisez pas par 0, vous ne produirez jamais d'exception et vous ne devrez pas gérer ce cas d'exception, car cela n'arrivera jamais. Dans le cas de l'accès à un fichier, toutefois, réussir une fois ne signifie pas que vous réussirez la prochaine fois: l'utilisateur peut avoir modifié les autorisations, un autre processus peut l'avoir supprimé ou modifié. Donc, vous devez toujours gérer ce cas exceptionnel, ou vous avez probablement un bogue.
la source
Pour les applications autonomes. Lorsque vous savez que votre application ne peut pas gérer l'exception, vous pouvez, au lieu de lancer l'exception RuntimeException cochée, lancer Error, laisser l'application planter, espérer des rapports de bogues et réparer votre application. (Voir la réponse de mrmuggles pour une discussion plus approfondie sur les avantages et les inconvénients de coché ou non coché.)
la source
C'est une pratique courante dans de nombreux cadres. Eg
Hibernate
fait exactement cela. L'idée est que les API ne doivent pas être intrusives pour le côté client etException
sont intrusives car vous devez écrire explicitement du code pour les manipuler à l'endroit où vous appelez l'API. Mais cet endroit pourrait ne pas être le bon endroit pour gérer l'exception en premier lieu.En fait, pour être honnête, il s’agit d’un sujet «brûlant» et de nombreux différends. Je ne prendrai donc pas parti pour cela, mais je dirai que ce que votre ami fait / propose n’est pas inhabituel ou inhabituel.
la source
Toute "chose vérifiée" est une mauvaise idée.
La programmation structurée permet uniquement aux informations d'être transmises (ou, en java, aux méthodes) lorsqu'elles sont "proches". Plus précisément, les informations ne peuvent circuler entre les fonctions que de deux manières:
D'appelant à appelé, en passant d'argument.
De l'appelé à l'appelant, en tant que valeurs de retour.
C'est une chose fondamentalement bonne. C'est ce qui vous permet de raisonner localement sur votre code: si vous avez besoin de comprendre ou de modifier une partie de votre programme, il vous suffit de regarder cette partie et les autres "proches".
Cependant, dans certaines circonstances, il est nécessaire d’envoyer des informations à une fonction "distante", sans que quiconque "sache" au milieu. C’est précisément le moment où des exceptions doivent être utilisées. Une exception est un message secret envoyé par un leveur (toute partie de votre code pouvant contenir une
throw
instruction) à un gestionnaire (toute partie de votre code pouvant contenir uncatch
bloc compatible avec l'exception qui étaitthrow
n).Les exceptions vérifiées détruisent le secret du mécanisme et, avec lui, la raison même de son existence. Si une fonction peut se permettre de laisser son appelant "connaître" une information, envoyez-la directement en tant que partie de la valeur de retour.
la source
Cela peut dépendre de cas à cas. Dans certains scénarios, il est sage de faire ce que fait votre ami, par exemple lorsque vous exposez une API pour certains clients et que vous souhaitez que le client soit moins au courant des détails de la mise en œuvre, sachant que certaines exceptions peuvent être spécifiques à la mise en œuvre. détails de mise en œuvre et non exposés au client.
En gardant les exceptions vérifiées à l'écart, vous pouvez exposer des API permettant au client d'écrire du code plus propre, car le client lui-même pourrait pré-valider les conditions exceptionnelles.
Par exemple, Integer.parseInt (String) prend une chaîne, renvoie son équivalent entier et lève une exception NumberFormatException si la chaîne n'est pas numérique. Imaginons maintenant qu'une soumission de formulaire avec un champ
age
soit convertie via cette méthode, mais que le client se soit déjà assuré de la validation. Il est donc inutile de forcer la vérification de l'exception.la source
Il y a vraiment quelques questions ici
La règle générale est que les exceptions que l'appelant doit intercepter et récupérer doivent être vérifiées. Les autres exceptions (celles dans lesquelles le seul résultat raisonnable est d'abandonner toute l'opération ou si vous les considérez suffisamment improbables pour que leur gestion spécifique ne vaille pas la peine) devraient être décochées.
Parfois, votre jugement sur le point de savoir si une exception mérite une capture et la récupération est différent de celui de l'API avec laquelle vous travaillez. Parfois, le contexte compte, une exception qui vaut la peine d’être traitée dans une situation donnée peut ne pas valoir la peine d’être traitée dans une autre. Parfois, votre main est forcée par les interfaces existantes. Donc oui, il y a des raisons légitimes de transformer une exception vérifiée en une exception non vérifiée (ou en un type différent d'exception vérifiée)
Tout d’abord et surtout, assurez-vous d’utiliser le système de chaînage d’exceptions. Ainsi, les informations de l'exception d'origine ne sont pas perdues et peuvent être utilisées pour le débogage.
Deuxièmement, vous devez choisir le type d’exception à utiliser. L'utilisation d'une exception d'exécution simple complique la tâche de l'appelant pour déterminer ce qui s'est mal passé, mais si l'appelant tente de déterminer ce qui s'est mal passé, cela peut indiquer que vous n'auriez pas dû modifier l'exception pour la décocher.
la source
Dans une question booléenne, il est difficile de répondre différemment après deux réponses controversées, mais je voudrais vous donner une perspective qui, même mentionnée à quelques endroits, n’a pas été suffisamment soulignée pour l’importance qu’elle revêt.
Au fil des années, j’ai constaté qu’il y avait toujours de la confusion chez un individu au sujet d’un problème trivial, mais il lui manquait une compréhension de certains des principes fondamentaux.
Superposition. Une application logicielle (du moins supposée être) est une pile de couches superposées. Une des attentes importantes pour une bonne superposition est que les couches inférieures fournissent des fonctionnalités pour potentiellement plusieurs composants de la couche supérieure.
Supposons que votre application comporte les couches suivantes: NET, TCP, HTTP, REST, MODÈLE DE DONNÉES, BUSINESS.
Si votre couche métier souhaite exécuter un appel en attente ... attendez une seconde. Pourquoi j'ai dit ça? Pourquoi n'ai-je pas dit requête HTTP ou transaction TCP ni envoyé de paquet réseau? Parce que ceux-ci ne sont pas pertinents pour ma couche métier. Je ne vais pas les gérer, je ne vais pas regarder dans les détails d'eux. Je suis parfaitement d'accord s'ils sont au cœur des exceptions que j'ai comme cause et je ne veux pas savoir qu'elles existent même.
De plus, c’est mauvais si je connais les détails, car si demain je voudrais changer les protocoles de transport soulignés qui traitent de détails spécifiques au protocole TCP, mon abstraction REST n’a pas fait du bon travail pour s’abstenir. la mise en œuvre spécifique.
Lors du passage d'une exception d'une couche à l'autre, il est important de revenir sur chaque aspect de celle-ci et de déterminer le sens que cela donnera à l'abstraction fournie par la couche actuelle. Cela pourrait être de remplacer l'exception par une autre, cela pourrait combiner plusieurs exceptions. Cela pourrait également les faire passer de coché à non coché ou vice versa.
Bien sûr, les lieux réels que vous avez mentionnés ont-ils du sens, est-ce une histoire différente, mais en général - oui, cela pourrait être une bonne chose à faire.
la source
À mon avis,
Au niveau de la structure, nous devrions être des exceptions d’exécution, afin de réduire davantage le nombre de tentatives d’attrape effectuées par l’invocateur au même endroit.
Au niveau de l'application, nous capturons rarement les exceptions d'exécution et je pense que cette pratique était mauvaise.
la source