Depuis plusieurs années, je ne parviens pas à obtenir une réponse décente à la question suivante : pourquoi certains développeurs sont-ils si opposés aux exceptions vérifiées ? J'ai eu de nombreuses conversations, j'ai lu des choses sur des blogs, j'ai lu ce que Bruce Eckel avait à dire (la première personne que j'ai vue s'exprimer contre elles).
Je suis en train d'écrire un nouveau code et je fais très attention à la façon dont je traite les exceptions. J'essaie de comprendre le point de vue de la foule "nous n'aimons pas les exceptions vérifiées" et je n'y arrive toujours pas.
Toutes les conversations que j'ai se terminent par la même question qui reste sans réponse... Laissez-moi vous expliquer :
En général (d'après la façon dont Java a été conçu),
-
Error
est pour les choses qui ne devraient jamais être prises (VM est allergique aux cacahuètes et quelqu'un a fait tomber un pot de cacahuètes sur lui) -
RuntimeException
est pour les choses que le programmeur a mal faites (le programmeur a oublié la fin d'un tableau). -
Exception
(saufRuntimeException
) est pour les choses qui sont hors du contrôle du programmeur (le disque se remplit lors de l'écriture dans le système de fichiers, la limite du gestionnaire de fichiers pour le processus a été atteinte et vous ne pouvez plus ouvrir de fichiers). -
Throwable
est simplement le parent de tous les types d'exception.
Un argument courant que j'entends est que si une exception se produit, tout ce que le développeur va faire est de quitter le programme.
Un autre argument courant que j'entends est que les exceptions vérifiées rendent plus difficile le remaniement du code.
Pour l'argument "tout ce que je vais faire est de quitter", je dis que même si vous quittez, vous devez afficher un message d'erreur raisonnable. Si vous vous contentez de gérer les erreurs, vos utilisateurs ne seront pas très heureux lorsque le programme quittera sans indication claire de la raison.
Pour ceux qui pensent que "cela rend difficile le remaniement", cela indique que le niveau d'abstraction approprié n'a pas été choisi. Plutôt que de déclarer qu'une méthode lance un IOException
le IOException
devrait être transformée en une exception plus adaptée à ce qui se passe.
Je n'ai pas de problème à envelopper Main avec catch(Exception)
(ou dans certains cas catch(Throwable)
afin de s'assurer que le programme peut se terminer de manière élégante - mais j'attrape toujours les exceptions spécifiques dont j'ai besoin. Cela me permet, au minimum, d'afficher un message d'erreur approprié.
La question à laquelle les gens ne répondent jamais est la suivante :
Si vous lancez
RuntimeException
au lieu deException
des sous-classes, alors comment savoir ce que vous êtes censé attraper ?
Si la réponse est catch Exception
alors vous traitez les erreurs du programmeur de la même manière que les exceptions du système. Cela me semble erroné.
Si vous attrapez Throwable
alors vous traitez les exceptions système et les erreurs VM (et autres) de la même manière. Cela me semble erroné.
Si la réponse est que vous n'attrapez que les exceptions que vous savez être levées, comment savez-vous lesquelles ? Que se passe-t-il lorsque le programmeur X lance une nouvelle exception et oublie de l'attraper ? Cela me semble très dangereux.
Je dirais qu'un programme qui affiche une trace de la pile est mauvais. Les personnes qui n'aiment pas les exceptions vérifiées ne sont-elles pas de cet avis ?
Donc, si vous n'aimez pas les exceptions contrôlées, pouvez-vous expliquer pourquoi et répondre à la question qui n'a pas reçu de réponse ?
Je ne cherche pas à savoir quand utiliser l'un ou l'autre modèle, ce que je cherche c'est pourquoi les personnes s'étendent de RuntimeException
parce qu'ils n'aiment pas s'étendre de Exception
et/ou pourquoi ils attrapent une exception et relancent ensuite une RuntimeException
plutôt que d'ajouter des lancers à leur méthode. Je veux comprendre les raisons pour lesquelles on n'aime pas les exceptions vérifiées.
47 votes
Je ne pense pas que ce soit complètement subjectif - c'est une fonctionnalité de la langue qui a été conçue pour avoir une utilisation spécifique, plutôt que pour que chacun puisse décider de ce à quoi elle sert pour lui-même. Et ce n'est pas spécialement argumentatif, ça répond à l'avance à des réfutations spécifiques que les gens auraient pu facilement trouver.
7 votes
Allez. Considéré comme une caractéristique de la langue, ce sujet a été et peut être abordé de manière objective.
6 votes
@cletus "répondre à votre propre question" si j'avais la réponse je n'aurais pas posé la question !
2 votes
Je suis d'accord pour que ce soit CW. Il n'y a pas de "bonne" réponse ; c'est une question de méthodologie et de pratiques. Je ne suis cependant pas d'accord pour dire qu'il devrait être fermé. C'est un débat important, et plus il y a d'opinions sur le sujet, mieux c'est, selon moi.
2 votes
Je ne demande pas la "bonne réponse sur la méthodologie et les pratiques", je demande le raisonnement des personnes qui choisissent cette méthodologie particulière. Je n'ai pas demandé les mérites relatifs entre les différentes façons de traiter les exceptions. Ce n'est pas non plus CW IMO, mais une comparaison entre les deux.
9 votes
Excellente question. En C++, il n'y a pas du tout d'exceptions vérifiées et, à mon avis, cela rend la fonction d'exception inutilisable. Vous vous retrouvez dans une situation où vous devez mettre un catch autour de chaque appel de fonction que vous faites, parce que vous ne savez pas s'il pourrait lancer quelque chose.
1 votes
@TofuBeer : vous êtes chemin Réflexion excessive : posez-vous la question suivante : où les exceptions vérifiées entrent-elles en jeu au niveau OOA/OOD et comment se fait-il que 95% des langages soient parfaitement satisfaits sans le concept brisé des exceptions vérifiées ? Les exceptions vérifiées sont une idiosynchrasie Java avec laquelle les gens doivent composer parce qu'il y a des API cassées qui ont été écrites autour de ce concept cassé. Une base de code de 200KLOC ici. Nous avons défini zéro vérifié l'exception et nous jetons zéro exception vérifiée. Et notre OOP est proche de notre OOA/OOD. C'est pourquoi nous ne les aimons pas.
3 votes
Le C++ est cassé sans exceptions vérifiées (IMO) - combien de fois voyez-vous catch(...) juste pour s'assurer que les choses ne se plantent pas. Donc, puisque vous avez une grande base de code, répondez s'il vous plaît à la question simple - comment vous assurez-vous que vous ne manquez aucune exception ? Disons que vous ajoutez une nouvelle "FooException" - comment vous assurez-vous que votre programme ne se plante pas si vous ne l'attrapez pas ? Comment l'attraper à tous les bons endroits ?
1 votes
L'utilisation du TDD et des exceptions de rutime résout le problème des exceptions vérifiées (si l'on craint de manquer quelque chose). Mais malheureusement, les librairies centrales de Java elles-mêmes vous obligent à attraper ces exceptions, ce qui rend votre code plus gros, souvent sans raison. Je pense que l'utilisation de AOP/spring peut également résoudre certains problèmes - une sorte de quelque chose au-dessus de java.
2 votes
@ses TDD ne résolvent pas le problème à moins de regarder l'ensemble du code source pour savoir ce qu'il faut tester. Cela fonctionne pour la personne qui écrit le code qui lance l'exception RuntimeException, mais pas pour la personne qui écrit le code qui appelle le code qui la lance. Partez du principe que votre programme ne peut pas se planter, jamais, alors quel est l'intérêt des RuntimeExceptions ?
0 votes
@TofuBeer La personne qui écrit le code, ne sait pas avec certitude que la personne (client) qui utiliserait ce code devrait vérifier cette exception. parce que cela dépend du cas ce que le client pense à ce sujet. Le client lui-même peut décider, en lisant la définition de la méthode qui lance RuntimeException où il veut l'attraper ou non. C'est juste. C'est le respect du temps du client et du code du clinet. En particulier, je ne vois pas la raison d'utiliser CheckedExceptions dans les méthodes d'interface, quand 1000 classes l'implémentent, dont 500 ne lèvent pas cette exception du tout, mais que le client doit quand même l'attraper.
0 votes
@TofuBeer si le client du code utilise TDD, cela l'aide à éviter les mauvais cas.
2 votes
@ses clients ne seront pas nécessairement au courant de l'exception d'exécution, il n'y a aucune obligation de documenter les exceptions d'exécution. Si le client ne sait pas, comment peut-il prendre une décision éclairée ? De plus, je pars du principe que le programme ne peut jamais se planter. Les exceptions d'exécution ne s'y prêtent pas.
0 votes
@TofuBeer Le client pourrait aussi ne pas savoir comment s'y prendre. C'est ce qui arrive tout le temps. Le client avale tout jusqu'à ce qu'il ait un problème. Alors le client devrait connaître l'exception / et ce qu'il va utiliser - et ce que fait la méthode. Dès qu'il en a connaissance, il peut décider de ce qu'il veut en faire.
2 votes
Et le client sera informé de l'exception comment exactement ? Suivez-le jusqu'à la conclusion logique. Je vous donne la bibliothèque X, vous appelez la méthode y de la classe Z. Quelles exceptions d'exécution devez-vous attraper ?
0 votes
Personnellement, j'aime beaucoup les exceptions vérifiées, elles m'aident à reconnaître très tôt les problèmes potentiels dans mon code. Mais ce que je déteste, c'est que la déclaration throws fait également partie des signatures de fonctions. Cela peut vraiment vous mettre dans un problème sans solution du tout. C'est la chose que je pense que la plupart des programmeurs n'aiment pas.
0 votes
En lisant son contrat ? Les exceptions font partie du contrat d'une méthode, qu'elles soient vérifiées ou non. Vous attrapez les exceptions pour lesquelles vous pouvez réellement faire quelque chose.
2 votes
C'est le problème @Kevin, si vous ajoutez une bibliothèque tierce qui ne documente pas les exceptions, que se passe-t-il ? Le but des exceptions vérifiées est d'éviter les erreurs des programmeurs... utiliser des exceptions non vérifiées pour des choses qui devraient être traitées (des choses qui ne sont pas des erreurs de programmeurs) annule cela.
0 votes
@TofuBeer Même si vous utilisez des exceptions vérifiées, si vous ne documentez pas les exceptions (en dehors de l'en-tête de la méthode elle-même) et les conditions spécifiques dans lesquelles elles se produisent, ils ne sauront pas non plus comment traiter vos exceptions. Le problème n'est pas celui des exceptions vérifiées ou non vérifiées, mais celui de la documentation.
3 votes
Les exceptions vérifiées encouragent la documentation et, dans le cas où elles ne sont pas documentées, elles sont toujours connues. Les exceptions non vérifiées peuvent plus facilement ne pas être documentées et, pire, ne pas être connues jusqu'à ce qu'elles se produisent dans un environnement de production.
0 votes
@DimitriC. C'est ce que je ressens en tant que développeur C# maintenant !
0 votes
"La VM est allergique aux cacahuètes et quelqu'un a fait tomber un pot de cacahuètes sur elle" - Oui, vous voulez vraiment que votre machine meure sans possibilité de récupération aux moments les plus critiques... Je ne vois rien de mal à ça... NE JAMAIS UTILISER L'ERREUR
0 votes
Il semble que personne n'ait remarqué le problème des interfaces. Si vous implémentez une interface, vous ne pouvez lancer que les exceptions qui sont déclarées dans l'interface. Il est donc impossible de réagir à une erreur avec une exception vérifiée dans de nombreux cas différents. Voir ma réponse.
6 votes
L'argument le plus fort que je connaisse pour Les exceptions vérifiées sont qu'elles n'existaient pas à l'origine dans Java, et que lorsqu'elles ont été introduites, elles ont permis de découvrir des centaines de bogues dans le JDK. Ceci est quelque peu antérieur à Java 1.0. Personnellement, je ne m'en passerais pas, et je suis en désaccord total avec Bruce Eckel et d'autres sur ce point.
1 votes
@user207421 D'après mon expérience, presque tout ce que Bruce Eckel dit est faux quand il s'agit de Java...
1 votes
Voici la question. De nombreuses bibliothèques ne lèvent pas d'exceptions vérifiées, de sorte que le programmeur n'est pas conscient de tout ce qui peut mal tourner et ne peut pas s'y préparer. A moins qu'il/elle ne lise le code source, mais qui lit une quelconque documentation ? À moins qu'il ne teste très soigneusement, mais qui élabore des tests comme s'il s'agissait d'une chose très importante ? Aux deux questions, je pense que la réponse est très peu.