499 votes

Les arguments contre les exceptions vérifiées

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 (sauf RuntimeException ) 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 de Exception 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 !

4voto

Chuck Conway Points 10293

Anders parle des pièges des exceptions vérifiées et des raisons pour lesquelles il les a laissées hors du C# en épisode 97 de la radio du génie logiciel.

4voto

Joshua Points 13231

Mon article sur c2.com n'a pratiquement pas changé par rapport à sa forme originale : CheckedExceptionsAreIncompatibleWithVisitorPattern

En résumé :

Le modèle Visitor et ses apparentés sont une classe d'interfaces où l'appelant indirect et la mise en œuvre de l'interface sont tous deux au courant d'une exception, mais où l'interface et l'appelant direct forment une bibliothèque qui ne peut pas le savoir.

L'hypothèse fondamentale de CheckedExceptions est que toutes les exceptions déclarées peuvent être levées à partir de n'importe quel point qui appelle une méthode avec cette déclaration. Le modèle VisitorPattern révèle que cette hypothèse est erronée.

Le résultat final des exceptions vérifiées dans des cas comme ceux-ci est un grand nombre de code inutile qui supprime essentiellement la contrainte d'exception vérifiée du compilateur au moment de l'exécution.

Quant au problème de fond :

Mon idée générale est que le gestionnaire de premier niveau doit interpréter l'exception et afficher un message d'erreur approprié. Je vois presque toujours des exceptions d'E/S, des exceptions de communication (pour une raison quelconque, les API se distinguent), ou des erreurs fatales à la tâche (bogues de programme ou problème grave sur le serveur de soutien), donc cela ne devrait pas être trop difficile si nous autorisons une trace de pile pour un problème grave du serveur.

3voto

oxbow_lakes Points 70013

Je pense que c'est une excellente question et qu'elle n'est pas du tout argumentée. Je pense que les bibliothèques tierces devraient (en général) jeter non vérifié exceptions. Cela signifie que vous pouvez isoler vos dépendances de la bibliothèque (c'est-à-dire que vous n'avez pas besoin de relancer leurs exceptions ou de lancer Exception - généralement une mauvaise pratique). Les Couche DAO en est un excellent exemple.

D'autre part, les exceptions provenant de l'API Java de base devraient en général être vérifiées si elles pourraient jamais être manipulé. Prenez FileNotFoundException ou (mon préféré) InterruptedException . Ces conditions doivent presque toujours être traitées de manière spécifique (c'est-à-dire que votre réaction à une InterruptedException n'est pas la même que votre réaction à une IllegalArgumentException ). Le fait que vos exceptions soient vérifiées oblige les développeurs à réfléchir pour savoir si une condition est gérable ou non. (Cela dit, j'ai rarement vu InterruptedException manipulés correctement !)

Une dernière chose - un RuntimeException n'est pas toujours "l'endroit où un développeur s'est trompé". Une exception pour argument illégal est levée lorsque vous essayez de créer un fichier enum en utilisant valueOf et il n'y a pas enum de ce nom. Il ne s'agit pas nécessairement d'une erreur du développeur !

3voto

Powerlord Points 43989

Un problème avec les exceptions vérifiées est que les exceptions sont souvent attachées aux méthodes d'une interface si une seule implémentation de cette interface l'utilise.

Un autre problème des exceptions vérifiées est qu'elles ont tendance à être mal utilisées. L'exemple parfait de ce problème se trouve dans java.sql.Connection 's [close()](http://java.sun.com/javase/6/docs/api/java/sql/Connection.html#close()) méthode. Elle peut lancer un SQLException même si vous avez déjà explicitement indiqué que vous en avez fini avec la Connexion. Quelles sont les informations que close() pourrait transmettre et qui vous intéressent ?

Habituellement, lorsque je ferme() une connexion * ça ressemble à quelque chose comme ça :

try {
    conn.close();
} catch (SQLException ex) {
    // Do nothing
}

De plus, ne me lancez pas sur les diverses méthodes d'analyse et sur NumberFormatException... La méthode TryParse de .NET, qui ne lève pas d'exceptions, est tellement plus facile à utiliser qu'il est pénible de devoir revenir à Java (nous utilisons à la fois Java et C# dans mon travail).

* En outre, la fonction Connection.close() d'une PooledConnection n'a même pas besoin d'être activée. fermer une connexion, mais vous devez quand même attraper l'exception SQLException, car il s'agit d'une exception vérifiée.

3voto

Aleksandr Dubinsky Points 2488

Le programmeur doit savoir tous des exceptions qu'une méthode peut lever, afin de l'utiliser correctement. Ainsi, le fait de lui asséner une partie seulement des exceptions n'aide pas nécessairement un programmeur négligent à éviter les erreurs.

L'avantage minime est compensé par le coût lourd (en particulier dans les bases de code plus grandes et moins flexibles où la modification constante des signatures d'interface n'est pas pratique).

L'analyse statique peut être intéressante, mais une analyse statique vraiment fiable exige souvent un travail rigoureux de la part du programmeur. Il y a un calcul coût-bénéfice, et la barre doit être placée haut pour une vérification qui conduit à une erreur de compilation. Il serait plus utile que l'IDE se charge de communiquer les exceptions qu'une méthode peut lancer (y compris celles qui sont inévitables). Même si cela ne serait peut-être pas aussi fiable sans déclaration obligatoire des exceptions, la plupart des exceptions seraient toujours déclarées dans la documentation, et la fiabilité d'un avertissement de l'IDE n'est pas si cruciale.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X