Les exceptions vérifiées de Java ont obtenu une mauvaise presse au fil des ans. Un signe révélateur est que c'est littéralement la seule langue au monde qui les possède (pas même d'autres langues JVM comme Groovy et Scala). Des bibliothèques Java importantes comme Spring et Hibernate ne les utilisent pas non plus.
J'ai personnellement trouvé une utilisation pour eux ( dans la logique métier entre les couches), mais sinon je suis des exceptions assez anti-vérifiées.
Y a-t-il d'autres utilisations que je ne réalise pas?
java
exceptions
errors
Brad Cupit
la source
la source
Réponses:
Tout d'abord, comme tout autre paradigme de programmation, vous devez le faire correctement pour qu'il fonctionne bien.
Pour moi, l'avantage des exceptions vérifiées est que les auteurs de la bibliothèque d'exécution Java ont DÉJÀ décidé pour moi quels problèmes courants on pourrait raisonnablement s'attendre à pouvoir gérer au point d' appel (par opposition à un catch-print de niveau supérieur) mourir) et réfléchissez le plus tôt possible à la manière de traiter ces problèmes.
J'aime les exceptions vérifiées car elles rendent mon code plus robuste en me forçant à penser à la récupération d'erreur le plus tôt possible.
Pour être plus précis, pour moi cela rend mon code plus robuste que cela me oblige à considérer les cas d'angle étrange très tôt dans le processus , par opposition à dire « Oops, mon code ne gère pas si le fichier n'existe pas encore » basé sur une erreur de production, que vous devez ensuite retravailler votre code pour gérer. L'ajout de la gestion des erreurs au code existant peut être une tâche non triviale - et donc coûteuse - lors de la maintenance plutôt que de le faire dès le début.
Il se peut que le fichier manquant soit fatal et doive provoquer le plantage du programme en flammes, mais ensuite vous prenez cette décision avec
Cela montre également un effet secondaire très important. Si vous encapsulez une exception, vous pouvez ajouter une explication qui va dans le stack-trace ! C'est extrêmement puissant car vous pouvez ajouter des informations sur, par exemple, le nom du fichier manquant, ou les paramètres passés à cette méthode ou d'autres informations de diagnostic, et ces informations sont présentes directement dans la trace de la pile, ce qui est souvent la seule chose que vous obtenir lorsqu'un programme est tombé en panne.
Les gens peuvent dire "nous pouvons simplement exécuter cela dans le débogueur pour reproduire", mais j'ai constaté que très souvent, les erreurs de production ne peuvent pas être reproduites plus tard, et nous ne pouvons pas exécuter les débogueurs en production, sauf dans les cas très désagréables où essentiellement votre travail est en jeu.
Plus il y a d'informations dans votre trace de pile, mieux c'est. Les exceptions vérifiées m'aident à obtenir ces informations là-bas, et tôt.
EDIT: Cela vaut également pour les concepteurs de bibliothèques. Une bibliothèque que j'utilise quotidiennement contient de nombreuses exceptions vérifiées qui auraient pu être conçues beaucoup mieux, ce qui la rendrait moins fastidieuse à utiliser.
la source
Vous avez deux bonnes réponses qui expliquent quelles exceptions vérifiées sont devenues dans la pratique. (+1 aux deux.) Mais il serait également utile d'examiner ce à quoi ils étaient destinés en théorie, car l'intention en vaut la peine.
Les exceptions vérifiées sont en fait destinées à rendre le langage plus sûr. Considérez une méthode simple comme la multiplication d'entiers. Vous pourriez penser que le type de résultat de cette méthode serait un entier, mais, à strictement parler, le résultat est soit un entier soit une exception de dépassement de capacité. La prise en compte du résultat entier en tant que type de retour de la méthode n'exprime pas la plage complète de la fonction.
Vu sous cet angle, il n'est pas strictement vrai de dire que les exceptions vérifiées n'ont pas trouvé leur chemin dans d'autres langues. Ils n'ont tout simplement pas pris la forme utilisée par Java. Dans les applications Haskell, il est courant d'utiliser des types de données algébriques pour distinguer entre la réussite et l'échec de la fonction. Bien qu'il ne s'agisse pas d'une exception, en soi, l'intention est très similaire à une exception vérifiée; il s'agit d'une API conçue pour forcer le consommateur d'API à gérer à la fois le succès en cas d'échec, par exemple:
Cela indique au programmeur que la fonction a deux résultats possibles supplémentaires en plus du succès.
la source
OMI, les exceptions vérifiées sont une implémentation imparfaite de ce qui aurait pu être une idée assez décente (dans des circonstances complètement différentes - mais ce n'est vraiment pas une bonne idée dans les circonstances actuelles).
La bonne idée est qu'il serait bien que le compilateur vérifie que toutes les exceptions qu'un programme a le potentiel de lever seront interceptées. L'implémentation imparfaite est que pour ce faire, Java vous oblige à traiter l'exception directement dans la classe qui appelle tout ce qui est déclaré pour lever une exception vérifiée. L'une des idées (et avantages) les plus élémentaires de la gestion des exceptions est qu'en cas d'erreur, elle permet aux couches intermédiaires de code qui n'ont rien à voir avec une erreur particulière, d'ignorer complètement son existence même. Les exceptions vérifiées (mises en œuvre en Java) ne permettent pas cela, détruisant ainsi un avantage majeur (le principal?) De la gestion des exceptions.
En théorie, ils auraient pu rendre les exceptions vérifiées utiles en les appliquant uniquement à l'échelle du programme - c'est-à-dire, tout en "construisant" le programme, construisez une arborescence de tous les chemins de contrôle dans le programme. Divers nœuds de l'arborescence seraient annotés avec 1) des exceptions qu'ils peuvent générer et 2) des exceptions qu'ils peuvent intercepter. Pour vous assurer que le programme était correct, vous parcourriez alors l'arbre, en vérifiant que chaque exception levée à n'importe quel niveau de l'arbre a été interceptée à un niveau supérieur dans l'arbre.
La raison pour laquelle ils ne l'ont pas fait (je suppose, de toute façon) est que cela serait atrocement difficile - en fait, je doute que quiconque ait écrit un système de construction qui puisse le faire pour autre chose que extrêmement simple (à la limite de "jouet") ") langages / systèmes. Pour Java, des choses comme le chargement dynamique des classes le rendent encore plus difficile que dans de nombreux autres cas. Pire, (contrairement à quelque chose comme C), Java n'est pas (au moins normalement) compilé / lié statiquement à un exécutable. Cela signifie que rien dans le système n'a vraiment la conscience mondiale d' essayer même de faire ce type d'application jusqu'à ce que l'utilisateur final commence réellement à charger le programme pour l'exécuter.
L'application de la loi à ce stade n'est pas pratique pour plusieurs raisons. Tout d'abord, même au mieux, cela allongerait les temps de démarrage, qui sont déjà l'une des plaintes les plus importantes et les plus courantes à propos de Java. Deuxièmement, pour faire beaucoup de bien, vous devez vraiment détecter le problème suffisamment tôt pour qu'un programmeur puisse le résoudre. Lorsque l'utilisateur charge le programme, il est trop tard pour faire beaucoup de bien - vos seuls choix à ce stade sont d'ignorer le problème ou de refuser de charger / exécuter le programme, au cas où il pourrait y avoir une exception. cela n'a pas été pris.
En l'état, les exceptions vérifiées sont pires qu'inutiles, mais les conceptions alternatives pour les exceptions vérifiées sont encore pires. Bien que l'idée de base des exceptions vérifiées semble bonne, elle n'est vraiment pas très bonne et s'avère être particulièrement mauvaise pour Java. Pour quelque chose comme C ++, qui est normalement compilé / lié en un exécutable complet avec rien de tel que le chargement de classe de réflexion / dynamique, vous auriez un peu plus de chance (bien que, franchement, même en les appliquant correctement sans le même genre de gâchis qu'ils actuellement à Java serait probablement encore au-delà de l'état actuel de la technique).
la source
UnexpectedException
type dérivé deRuntimeException
. Notez que "jette" et "ne s'attend pas" ne sont pas contradictoires; sifoo
jetteBozException
et appellebar
, cela ne signifie pas qu'il s'attendbar
à lancerBozException
.Ils sont vraiment bons pour ennuyer les programmeurs et encourager la déglutition d'exceptions. La moitié des exceptions est pour que vous ayez une manière saine et par défaut de gérer les erreurs et que vous n'ayez pas à penser à propager explicitement les conditions d'erreur que vous ne pouvez pas gérer. (La valeur par défaut est que si vous ne gérez jamais l'erreur nulle part dans votre code, vous avez effectivement affirmé que cela ne pouvait pas se produire et vous vous retrouvez avec une sortie saine et une trace de pile si vous vous trompez.) Les exceptions vérifiées sont vaincues. cette. Ils ont l'impression de devoir propager explicitement les erreurs en C.
la source
throws FileNotFoundException
. Correctif:catch (FileNotFoundException e) { throw RuntimeException(e); }
Je pense qu'il est juste de dire que les exceptions vérifiées étaient un peu une expérience ratée. Là où ils ont mal tourné, c'est qu'ils ont cassé les couches:
La belle séparation des concernés est rompue, car maintenant la connaissance des erreurs qui auraient pu être limitées à A et C doit maintenant être dispersée sur B.
Il y a une belle discussion sur les exceptions vérifiées sur Wikipedia.
Et Bruce Eckel a également un bel article à ce sujet. Voici une citation:
Je crois que pour le cas de C ++, si toutes les méthodes ont la
throws
clause de spécification, alors vous pouvez avoir de belles optimisations. Je ne pense pas que Java puisse avoir ces avantages de toute façon, carRuntimeExceptions
ils ne sont pas vérifiés. Un JIT moderne devrait être en mesure d'optimiser le code très bien de toute façon.Une caractéristique intéressante d'AspectJ est l'adoucissement des exceptions: vous pouvez transformer les exceptions cochées en exceptions non vérifiées, en particulier pour améliorer la superposition.
Il est peut-être ironique que Java ait traversé tous ces problèmes, alors qu'il aurait pu vérifier à la
null
place, ce qui aurait pu être beaucoup plus précieux .la source
J'adore les exceptions.
Je suis cependant constamment perplexe devant leur mauvaise utilisation.
Ne les utilisez pas pour la gestion des flux. Vous ne voulez pas de code qui essaie de faire quelque chose et utilise une exception comme déclencheur pour faire autre chose à la place, car les exceptions sont des objets qui doivent être créés et utiliser de la mémoire, etc., simplement parce que vous ne pourriez pas être dérangé d'en écrire sorte de vérifier si () avant de faire votre appel. C'est juste paresseux et donne à la glorieuse Exception une mauvaise réputation.
Ne les avalez pas. Déjà. Dans n'importe quelle circonstance. Au minimum, vous collez quelque chose dans votre fichier journal pour indiquer qu'une exception s'est produite. Essayer de suivre votre chemin à travers le code qui avale les exceptions est un cauchemar. Encore une fois, maudissez-vous les avaleurs d'exceptions pour avoir discrédité la puissante exception!
Traitez les exceptions avec votre chapeau OO. Créez vos propres objets Exception avec des hiérarchies significatives. Superposez votre logique métier et vos exceptions main dans la main. J'avais l'habitude de constater que si je commençais sur une nouvelle zone d'un système, je trouverais la nécessité de sous-classer l'exception dans la demi-heure suivant le codage, donc ces jours-ci, je commence par écrire les classes d'exception.
Si vous écrivez des morceaux de code «frameworky», assurez-vous que toutes vos interfaces initiales sont écrites pour lancer vos propres nouvelles exceptions le cas échéant ... et assurez-vous que vos codeurs ont un exemple de code à l'endroit où faire quand leur code lève une IOException mais l'interface vers laquelle ils écrivent veut lever une «ReportingApplicationException».
Une fois que vous aurez essayé de faire fonctionner les exceptions pour vous, vous ne regarderez jamais en arrière.
la source
initCause
ou initialisez l'exception avec l'exception qui l'a provoquée. Exemple: vous disposez d'un utilitaire d'E / S dont vous n'avez besoin que d'une exception si l'écriture échoue. Cependant, il existe plusieurs raisons pour lesquelles une écriture peut échouer (impossible d'accéder, erreur d'écriture, etc.) Lancez votre exception personnalisée avec la cause une afin que le problème d'origine ne soit pas avalé.Les exceptions vérifiées se trouvent également dans ADA.
(Attention, ce post contient des croyances fermement ancrées que vous pourriez rencontrer.)
Les programmeurs ne les aiment pas et se plaignent, ou écrivent du code de déglutition d'exception.
Les exceptions vérifiées existent parce que les choses peuvent non seulement ne pas fonctionner, vous pouvez faire une analyse du mode de défaillance / effets et déterminer cela à l'avance.
Les lectures de fichiers peuvent échouer. Les appels RPC peuvent échouer. Les E / S réseau peuvent échouer. Les données peuvent être mal formatées lors de l'analyse.
Le "chemin heureux" pour le code est facile.
Je connaissais un gars à l'Université qui pouvait écrire du bon code "happy path". Aucun des cas de bord n'a jamais fonctionné. Ces jours-ci, il fait du Python pour une entreprise open source. Dit Nuff.
Si vous ne voulez pas gérer les exceptions vérifiées, ce que vous dites vraiment, c'est
Les exceptions vérifiées ne seront donc pas appréciées par les programmeurs, car cela signifie plus de travail.
Bien sûr, d'autres personnes auraient pu souhaiter que ce travail soit fait.
Ils auraient pu vouloir la bonne réponse même si le serveur de fichiers est tombé en panne / la clé USB est morte.
C'est une étrange croyance dans la communauté de la programmation que vous devriez utiliser un langage de programmation qui vous facilite la vie, que vous appréciez, lorsque votre travail consiste à écrire des logiciels. Votre travail consiste à résoudre le problème de quelqu'un, ne vous permettant pas de vous lancer dans l'improvisation programmatique de Jazz.
Si vous êtes un programmeur amateur (pas de programmation pour de l'argent), n'hésitez pas à programmer en C # ou dans un autre langage sans aucune exception vérifiée. Heck, découpez l'homme du milieu et programmez en Logo. Vous pouvez dessiner de jolis motifs sur le sol avec la tortue.
la source
Les exceptions vérifiées auraient dû encourager les utilisateurs à gérer les erreurs proches de leur source. Plus vous vous éloignez de la source, plus les fonctions sont terminées au milieu de l'exécution et plus il est probable que le système soit entré dans un état incohérent. De plus, il est plus probable que vous tombiez sur la mauvaise exception par accident.
Malheureusement, les gens ont tendance à ignorer les exceptions ou à ajouter des spécifications de lancer toujours plus importantes. Ces deux éléments ne permettent pas de savoir ce que les exceptions vérifiées sont censées encourager. Ils sont comme transformer du code procédural pour utiliser de nombreuses fonctions Getter et Setter, ce qui en fait soi-disant OO.
Essentiellement, les exceptions vérifiées tentent de prouver un certain degré d'exactitude dans votre code. C'est à peu près la même idée que la frappe statique, en ce sens qu'elle tente de prouver que certaines choses sont correctes avant même que le code ne s'exécute. Le problème est que toutes ces preuves supplémentaires demandent un effort et est-ce que l'effort en vaut la peine?
la source