Quand choisir les exceptions cochées et non cochées

213

En Java (ou dans tout autre langage avec des exceptions vérifiées), lors de la création de votre propre classe d'exceptions, comment décidez-vous si elle doit être vérifiée ou décochée?

Mon instinct est de dire qu'une exception vérifiée serait demandée dans les cas où l'appelant pourrait être en mesure de récupérer d'une manière productive, alors qu'une exception non vérifiée serait plus pour les cas irrécupérables, mais je serais intéressé par les pensées des autres.

Matt Sheppard
la source
11
Barry Ruzek a écrit un excellent guide sur le choix des exceptions cochées ou non cochées.
sigget

Réponses:

241

Les exceptions vérifiées sont excellentes, tant que vous comprenez quand elles doivent être utilisées. L'API Java Core ne respecte pas ces règles pour SQLException (et parfois pour IOException), c'est pourquoi elles sont si terribles.

Les exceptions vérifiées doivent être utilisées pour les erreurs prévisibles mais non évitables dont il est raisonnable de se remettre .

Exceptions non vérifiées doivent être utilisées pour tout le reste.

Je vais vous expliquer cela, car la plupart des gens comprennent mal ce que cela signifie.

  1. Prévisible mais non évitable : l'appelant a fait tout ce qui était en son pouvoir pour valider les paramètres d'entrée, mais certaines conditions indépendantes de sa volonté ont entraîné l'échec de l'opération. Par exemple, vous essayez de lire un fichier mais quelqu'un le supprime entre le moment où vous vérifiez s'il existe et le moment où l'opération de lecture commence. En déclarant une exception vérifiée, vous dites à l'appelant d'anticiper cet échec.
  2. Raisonnable pour récupérer : il est inutile de dire aux appelants d'anticiper les exceptions qu'ils ne peuvent pas récupérer. Si un utilisateur tente de lire à partir d'un fichier inexistant, l'appelant peut lui demander un nouveau nom de fichier. En revanche, si la méthode échoue en raison d'un bogue de programmation (arguments de méthode invalides ou implémentation de méthode boguée), l'application ne peut rien faire pour résoudre le problème en cours d'exécution. Le mieux qu'il puisse faire est de consigner le problème et d'attendre que le développeur le corrige ultérieurement.

À moins que l'exception que vous lancez ne remplisse toutes les conditions ci-dessus, elle doit utiliser une exception non vérifiée.

Réévaluer à tous les niveaux : Parfois, la méthode de capture de l'exception vérifiée n'est pas le bon endroit pour gérer l'erreur. Dans ce cas, réfléchissez à ce qui est raisonnable pour vos propres appelants. Si l'exception est prévisible, impossible à prévenir et raisonnable pour eux de récupérer, vous devez alors lancer vous-même une exception vérifiée. Sinon, vous devez encapsuler l'exception dans une exception non cochée. Si vous suivez cette règle, vous vous retrouverez à convertir les exceptions cochées en exceptions non cochées et vice versa en fonction de la couche dans laquelle vous vous trouvez.

Pour les exceptions vérifiées et non contrôlées, utilisez le bon niveau d'abstraction . Par exemple, un référentiel de code avec deux implémentations différentes (base de données et système de fichiers) devrait éviter d'exposer des détails spécifiques à l'implémentation en lançant SQLExceptionou IOException. Au lieu de cela, il doit envelopper l'exception dans une abstraction qui couvre toutes les implémentations (par exemple RepositoryException).

Gili
la source
2
"vous essayez de lire un fichier mais quelqu'un le supprime entre le moment où vous vérifiez s'il existe et le moment où l'opération de lecture commence." => Comment est-ce même «attendu»? Pour moi, cela ressemble plus à: INattendu et évitable .. Qui s'attendrait à ce qu'un fichier soit supprimé juste entre 2 déclarations?
Koray Tugay
9
@KorayTugay Expected ne signifie pas que le scénario est typique. Cela signifie simplement que nous pouvons prévoir que cette erreur se produira à l'avance (par rapport aux erreurs de programmation qui ne peuvent pas être prédites à l'avance). Impossible à éviter fait référence au fait que le programmeur ne peut rien faire pour empêcher l'utilisateur ou d'autres applications de supprimer un fichier entre le moment où nous vérifions s'il existe et le moment où l'opération de lecture commence.
Gili
Donc, tous les problèmes liés à la base de données dans la méthode doivent lever l'exception vérifiée?
ivanjermakov
59

D' un apprenant Java :

Lorsqu'une exception se produit, vous devez soit intercepter et gérer l'exception, soit dire au compilateur que vous ne pouvez pas la gérer en déclarant que votre méthode lève cette exception, alors le code qui utilise votre méthode devra gérer cette exception (même peut également choisir de déclarer qu'il lève l'exception s'il ne peut pas la gérer).

Le compilateur vérifiera que nous avons fait l'une des deux choses (attraper ou déclarer). C'est ce qu'on appelle les exceptions vérifiées. Mais les erreurs et les exceptions d'exécution ne sont pas vérifiées par le compilateur (même si vous pouvez choisir d'intercepter ou de déclarer, ce n'est pas obligatoire). Donc, ces deux sont appelés exceptions non vérifiées.

Les erreurs sont utilisées pour représenter les conditions qui se produisent en dehors de l'application, comme le plantage du système. Les exceptions d'exécution se produisent généralement par défaut dans la logique d'application. Vous ne pouvez rien faire dans ces situations. Lorsqu'une exception d'exécution se produit, vous devez réécrire votre code de programme. Donc, ceux-ci ne sont pas vérifiés par le compilateur. Ces exceptions d'exécution seront découvertes pendant le développement et la période de test. Ensuite, nous devons refactoriser notre code pour supprimer ces erreurs.

Espo
la source
13
Voilà la vision orthodoxe. Mais il y a beaucoup de controverse à ce sujet.
artbristol
49

La règle que j'utilise est: ne jamais utiliser d'exceptions non contrôlées! (ou quand vous ne voyez aucun moyen de contourner cela)

Il existe un argument très solide pour le contraire: n'utilisez jamais d'exceptions vérifiées. J'hésite à prendre parti dans le débat, mais il semble y avoir un large consensus selon lequel l'introduction d'exceptions vérifiées était une mauvaise décision avec le recul. S'il vous plaît, ne tirez pas sur le messager et ne vous référez pas à ces arguments .

Konrad Rudolph
la source
3
À mon humble avis, les exceptions vérifiées auraient pu être un atout majeur s'il y avait eu un moyen facile pour une méthode de déclarer qu'elle ne s'attend pas à ce que les méthodes appelées dans un bloc de code particulier lèvent certaines exceptions (ou aucune), et que toute vérification les exceptions levées contrairement à une telle attente doivent être encapsulées dans un autre type d'exception et renvoyées. Je suppose que 90% du temps lorsque le code n'est pas prêt à faire face à une exception vérifiée, un tel bouclage et retour serait le meilleur moyen de le gérer, mais comme il n'y a pas de support de langue, c'est rarement fait.
supercat
@supercat C'est essentiellement ça: je suis un fan inconditionnel de la vérification stricte de type et les exceptions vérifiées en sont une extension logique. J'ai complètement abandonné les exceptions vérifiées même si je les aime beaucoup conceptuellement.
Konrad Rudolph
1
Un problème que j'ai avec la conception des exceptions, que le mécanisme que j'ai décrit résoudrait, est que s'il fooest documenté comme lançant barExceptionlors de la lecture après la fin d'un fichier et qu'il fooappelle une méthode qui lève barExceptionmême s'il foone s'y attend pas, le le code qui appelle foopensera que la fin du fichier a été atteinte et n'aura aucune idée que quelque chose d'inattendu s'est produit. Je considérerais cette situation comme étant celle où les exceptions vérifiées devraient être les plus utiles, mais c'est aussi le seul cas où le compilateur autorisera les exceptions vérifiées non gérées.
supercat
@supercat: il existe déjà un moyen simple pour le code de faire ce que vous voulez dans le premier commentaire: encapsuler le code dans un bloc try, intercepter l'exception et encapsuler l'exception dans une RuntimeException et relancer.
Warren Dew
1
@KonradRudolph supercat fait référence à "un bloc de code particulier"; étant donné que le bloc doit être défini, la syntaxe déclarative ne réduirait pas significativement le ballonnement. Si vous pensez que ce serait déclaratif pour l'ensemble de la fonction, cela encouragerait une mauvaise programmation car les gens resteraient dans la déclaration au lieu de regarder les exceptions vérifiées potentiellement interceptées, et de s'assurer qu'il n'y a pas d'autre meilleur moyen pour les gérer.
Warren Dew
46

Sur tout système assez grand, avec de nombreuses couches, les exceptions vérifiées sont inutiles car, de toute façon, vous avez besoin d'une stratégie de niveau architectural pour gérer la façon dont l'exception sera gérée (utilisez une barrière de défaillance)

Avec des exceptions vérifiées, votre stratégie de gestion des erreurs est micro-gérée et insupportable sur tout grand système.

La plupart du temps, vous ne savez pas si une erreur est "récupérable" car vous ne savez pas dans quelle couche se trouve l'appelant de votre API.

Disons que je crée une API StringToInt qui convertit la représentation sous forme de chaîne d'un entier en un Int. Dois-je lever une exception vérifiée si l'API est appelée avec la chaîne "foo"? Est-il récupérable? Je ne sais pas parce que dans sa couche, l'appelant de mon API StringToInt peut déjà avoir validé l'entrée, et si cette exception est levée, c'est soit un bug soit une corruption de données et elle n'est pas récupérable pour cette couche.

Dans ce cas, l'appelant de l'API ne veut pas intercepter l'exception. Il veut seulement laisser l'exception "bouillonner". Si j'ai choisi une exception vérifiée, cet appelant aura beaucoup de bloc de capture inutile uniquement pour renvoyer artificiellement l'exception.

Ce qui est récupérable dépend la plupart du temps de l'appelant de l'API, pas du rédacteur de l'API. Une API ne doit pas utiliser d'exceptions vérifiées car seules les exceptions non contrôlées permettent de choisir d'intercepter ou d'ignorer une exception.

Stéphane
la source
3
Ceci est très proche de userstories.blogspot.com/2008/12/…
alexsmail
16
@alexsmail Internet ne manque jamais de me surprendre, en fait c'est mon blog :)
Stephane
30

Vous avez raison.

Des exceptions non vérifiées sont utilisées pour laisser le système tomber en panne rapidement, ce qui est une bonne chose. Vous devez indiquer clairement à quoi s'attend votre méthode pour fonctionner correctement. De cette façon, vous ne pouvez valider l'entrée qu'une seule fois.

Par exemple:

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

Juste pour mettre un exemple. Le fait est que si le système tombe en panne rapidement, vous saurez où et pourquoi il a échoué. Vous obtiendrez une trace de pile comme:

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

Et vous saurez ce qui s'est passé. L'AutreClasse de la méthode "delegateTheWork" (à la ligne 4569) a appelé votre classe avec la valeur "exit", même si elle ne devrait pas etc.

Sinon, vous auriez à saupoudrer des validations sur tout votre code et cela est sujet aux erreurs. De plus, il est parfois difficile de suivre ce qui s'est mal passé et vous pouvez vous attendre à des heures de débogage frustrant

La même chose se produit avec NullPointerExceptions. Si vous avez une classe de 700 lignes avec quelque 15 méthodes, qui utilise 30 attributs et aucun d'entre eux ne peut être nul, au lieu de valider dans chacune de ces méthodes la nullité, vous pouvez rendre tous ces attributs en lecture seule et les valider dans le constructeur ou méthode d'usine.

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

Exceptions vérifiées sont utiles lorsque le programmeur (vous ou vos collègues) a tout fait correctement, validé l'entrée, exécuté des tests et que tout le code est parfait, mais le code se connecte à un service Web tiers qui peut être en panne (ou à un fichier que vous utilisiez a été supprimé par un autre processus externe, etc.). Le service Web peut même être validé avant que la connexion ne soit tentée, mais pendant le transfert de données, quelque chose s'est mal passé.

Dans ce scénario, vous ou vos collègues ne pouvez rien faire pour l'aider. Mais encore faut-il faire quelque chose et ne pas laisser l'application mourir et disparaître aux yeux de l'utilisateur. Vous utilisez une exception vérifiée pour cela et gérez l'exception, que pouvez-vous faire quand cela se produit?, La plupart du temps, juste pour tenter de consigner l'erreur, probablement enregistrer votre travail (le travail de l'application) et présenter un message à l'utilisateur . (Le site blabla est en panne, veuillez réessayer plus tard, etc.)

Si l'exception vérifiée est surutilisée (en ajoutant la "throw Exception" dans toutes les signatures de méthodes), alors votre code deviendra très fragile, car tout le monde ignorera cette exception (car il est trop général) et la qualité du code sera sérieusement compromis.

Si vous abusez d'une exception non contrôlée, quelque chose de similaire se produira. Les utilisateurs de ce code ne savent pas si quelque chose peut mal se passer. Beaucoup de tentatives {...} catch (Throwable t) apparaîtront.

OscarRyz
la source
2
Bien dit! +1. Cela me surprend toujours que cette distinction appelant (non cochée) / appelé (vérifié) n'est pas plus évidente ...
VonC
19

Voici ma «règle d'or finale».
J'utilise:

  • exception non vérifiée dans le code de ma méthode pour un échec dû à l'appelant (qui implique une documentation explicite et complète )
  • exception vérifiée pour un échec en raison de l' appelé que je dois expliquer à quiconque souhaite utiliser mon code

Par rapport à la réponse précédente, il s'agit d'une justification claire (sur laquelle on peut être d'accord ou en désaccord) pour l'utilisation de l'une ou l'autre (ou des deux) types d'exceptions.


Pour ces deux exceptions, je vais créer ma propre exception non vérifiée et vérifiée pour mon application (une bonne pratique, comme mentionné ici ), à l'exception des exceptions non vérifiées très courantes (comme NullPointerException)

Ainsi, par exemple, le but de cette fonction particulière ci-dessous est de créer (ou d'obtenir s'il existe déjà) un objet,
ce qui signifie:

  • le conteneur de l'objet à créer / obtenir DOIT exister (responsabilité de CALLER
    => exception non vérifiée, ET effacer le commentaire javadoc pour cette fonction appelée)
  • les autres paramètres ne peuvent pas être nuls
    (choix du codeur pour le mettre sur le CALLER: le codeur ne vérifiera pas le paramètre nul mais le codeur LE DOCUMENT)
  • le résultat NE PEUT PAS ÊTRE NUL
    (responsabilité et choix du code de l'appelé, choix qui sera d'un grand intérêt pour l'appelant
    => exception vérifiée car chaque appelant DOIT prendre une décision si l'objet ne peut pas être créé / trouvé, et que la décision doit être exécutée au moment de la compilation: ils ne peuvent pas utiliser cette fonction sans avoir à gérer cette possibilité, c'est-à-dire avec cette exception vérifiée ).

Exemple:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}
VonC
la source
19

Ce n'est pas seulement une question de capacité à se remettre de l'exception. À mon avis, ce qui importe le plus, c'est de savoir si l'appelant souhaite intercepter l'exception ou non.

Si vous écrivez une bibliothèque à utiliser ailleurs ou une couche de niveau inférieur dans votre application, demandez-vous si l'appelant souhaite intercepter (connaître) votre exception. Si ce n'est pas le cas, utilisez une exception non vérifiée pour ne pas le surcharger inutilement.

C'est la philosophie utilisée par de nombreux frameworks. Spring et hibernate, en particulier, viennent à l'esprit - ils convertissent l'exception vérifiée connue en exception non vérifiée précisément parce que les exceptions vérifiées sont surutilisées en Java. Un exemple auquel je peux penser est l'exception JSONException de json.org, qui est une exception vérifiée et généralement ennuyeuse - elle devrait être décochée, mais le développeur n'a tout simplement pas réfléchi.

Soit dit en passant, la plupart du temps, l'intérêt de l'appelant pour l'exception est directement lié à la capacité de se remettre de l'exception, mais ce n'est pas toujours le cas.

Yoni
la source
13

Voici une solution très simple à votre dilemme vérifié / non vérifié.

Règle 1: Considérez une exception non vérifiée comme une condition testable avant l'exécution du code. par exemple…

x.doSomething(); // the code throws a NullPointerException

où x est nul ... ... le code devrait éventuellement avoir ce qui suit ...

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

Règle 2: Considérez une exception vérifiée comme une condition non testable qui peut se produire pendant l'exécution du code.

Socket s = new Socket(“google.com”, 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

… Dans l'exemple ci-dessus, l'URL (google.com) peut ne pas être disponible en raison de la panne du serveur DNS. Même au moment où le serveur DNS fonctionnait et résolvait le nom «google.com» en une adresse IP, si la connexion est établie avec google.com, à tout moment après le mot de passe, le réseau pourrait tomber. Vous ne pouvez tout simplement pas tester le réseau tout le temps avant de lire et d'écrire dans des flux.

Il y a des moments où le code doit simplement s'exécuter avant que nous puissions savoir s'il y a un problème. En forçant les développeurs à écrire leur code de manière à les forcer à gérer ces situations via Checked Exception, je dois donner mon chapeau au créateur de Java qui a inventé ce concept.

En général, presque toutes les API en Java suivent les 2 règles ci-dessus. Si vous essayez d'écrire dans un fichier, le disque peut se remplir avant de terminer l'écriture. Il est possible que d'autres processus aient provoqué la saturation du disque. Il n'y a tout simplement aucun moyen de tester cette situation. Pour ceux qui interagissent avec du matériel où, à tout moment, l'utilisation du matériel peut échouer, les exceptions vérifiées semblent être une solution élégante à ce problème.

Il y a une zone grise à cela. Dans le cas où de nombreux tests sont nécessaires (une déclaration époustouflante si beaucoup de && et ||), l'exception levée sera une CheckedException simplement parce que c'est trop difficile de bien faire les choses - vous ne pouvez tout simplement pas dire ce problème est une erreur de programmation. S'il y a beaucoup moins de 10 tests (par exemple «if (x == null)»), l'erreur de programmation doit être une exception UncheckedException.

Les choses deviennent intéressantes lorsqu'il s'agit d'interprètes de langue. Selon les règles ci-dessus, une erreur de syntaxe doit-elle être considérée comme une exception vérifiée ou non vérifiée? Je dirais que si la syntaxe du langage peut être testée avant d'être exécutée, ce devrait être une exception UncheckedException. Si la langue ne peut pas être testée - similaire à la façon dont le code assembleur s'exécute sur un ordinateur personnel, l'erreur de syntaxe doit être une exception vérifiée.

Les 2 règles ci-dessus supprimeront probablement 90% de votre inquiétude quant au choix. Pour résumer les règles, suivez ce modèle… 1) si le code à exécuter peut être testé avant d'être exécuté pour qu'il s'exécute correctement et si une exception se produit - alias une erreur de programmeur, l'exception doit être une UncheckedException (une sous-classe de RuntimeException ). 2) si le code à exécuter ne peut pas être testé avant d'être exécuté pour qu'il s'exécute correctement, l'exception doit être une exception vérifiée (une sous-classe d'exception).

user3598189
la source
9

Vous pouvez l'appeler une exception cochée ou non cochée; cependant, les deux types d'exceptions peuvent être interceptés par le programmeur, donc la meilleure réponse est: écrivez toutes vos exceptions comme non vérifiées et documentez-les. De cette façon, le développeur qui utilise votre API peut choisir s'il veut intercepter cette exception et faire quelque chose. Les exceptions vérifiées sont une perte totale de temps pour tout le monde et cela fait de votre code un cauchemar choquant à regarder. Des tests unitaires appropriés feront ensuite apparaître toutes les exceptions que vous pourriez avoir à attraper et à faire avec.

Colin Saxton
la source
1
+1 Pour mentionner que les tests unitaires pourraient être un meilleur moyen de résoudre le problème, les exceptions vérifiées sont censées résoudre.
Keith Pinson
+1 pour les tests unitaires. L'utilisation d'exceptions vérifiées / non vérifiées a peu d'impact sur la qualité du code. Ainsi, l'argument selon lequel si l'on utilise des exceptions vérifiées entraînerait une meilleure qualité de code est un argument bidon complet!
user1697575
7

Exception vérifiée: si le client peut récupérer d'une exception et souhaite continuer, utilisez l'exception vérifiée.

Exception non vérifiée: si un client ne peut rien faire après l'exception, déclenchez une exception non vérifiée.

Exemple: Si vous devez effectuer une opération arithmétique dans une méthode A () et en fonction de la sortie de A (), vous devez effectuer une autre opération. Si la sortie est nulle à partir de la méthode A () à laquelle vous ne vous attendiez pas pendant l'exécution, vous devez alors lever l'exception de pointeur Null qui est une exception d'exécution.

Se référer ici

Objectifs
la source
2

Je suis d'accord avec la préférence pour les exceptions non contrôlées en règle générale, en particulier lors de la conception d'une API. L'appelant peut toujours choisir d'intercepter une exception documentée et non vérifiée. Vous ne forcez pas inutilement l'appelant à le faire.

Je trouve les exceptions vérifiées utiles au niveau inférieur, comme détail d'implémentation. Cela semble souvent être un meilleur mécanisme de contrôle du flux que d'avoir à gérer un "code retour" d'erreur spécifié. Cela peut parfois aider à voir l'impact d'une idée pour un changement de code de bas niveau aussi ... déclarer une exception vérifiée en aval et voir qui devrait s'ajuster. Ce dernier point ne s'applique pas s'il y a beaucoup de génériques: catch (Exception e) ou throw Exception qui n'est généralement pas trop bien pensé de toute façon.

Scott Kurz
la source
2

Voici que je veux partager mon opinion que j'ai après de nombreuses années d'expérience en développement:

  1. Exception vérifiée. Cela fait partie du cas d'utilisation métier ou du flux d'appels, c'est une partie de la logique d'application que nous attendons ou non. Par exemple, la connexion a été rejetée, la condition n'est pas satisfaite, etc. Je l'appelle habituellement exception de post-traitement ou exception "utilisateur".

  2. Exception non vérifiée. Cela fait partie de l'exception de programmation, une erreur de programmation de code logiciel (bogue, défaut) et reflète la manière dont les programmeurs doivent utiliser l'API conformément à la documentation. Si un document de bibliothèque / framework externe dit qu'il s'attend à obtenir des données dans une certaine plage et non null, car NPE ou IllegalArgumentException seront levées, le programmeur devrait s'y attendre et utiliser l'API correctement selon la documentation. Sinon, l'exception sera levée. Je l'appelle habituellement exception de prétraitement ou exception de «validation».

Par public cible. Parlons maintenant du public cible ou du groupe de personnes auquel les exceptions ont été conçues (à mon avis):

  1. Exception vérifiée. Le public cible est les utilisateurs / clients.
  2. Exception non vérifiée. Le public cible est les développeurs. En d'autres termes, les exceptions non vérifiées sont conçues pour les développeurs uniquement.

Par phase de cycle de vie de développement d'applications.

  1. L'exception vérifiée est conçue pour exister pendant tout le cycle de vie de la production en tant que mécanisme normal et attendu qu'une application gère des cas exceptionnels.
  2. Une exception non vérifiée est conçue pour exister uniquement pendant le cycle de développement / test de l'application, elles doivent toutes être corrigées pendant cette période et ne doivent pas être levées lorsqu'une application est déjà en cours de production.

La raison pour laquelle les frameworks utilisent généralement des exceptions non contrôlées (Spring par exemple) est que le framework ne peut pas déterminer la logique métier de votre application, il appartient aux développeurs de saisir et de concevoir leur propre logique.

Denys
la source
2

Nous devons distinguer ces deux types d'exceptions selon qu'il s'agit d'une erreur de programmeur ou non.

  • Si une erreur est une erreur de programmeur, il doit s'agir d'une exception non vérifiée . Par exemple: SQLException / IOException / NullPointerException. Ces exceptions sont des erreurs de programmation. Ils doivent être gérés par le programmeur. Alors que dans l'API JDBC, SQLException est une exception vérifiée, au printemps JDBCTemplate c'est une exception non vérifiée.Le programmeur ne se soucie pas de SqlException, lors de l'utilisation de Spring.
  • Si une erreur n'est pas une erreur du programmeur et que la raison provient de l'extérieur, il doit s'agir d'une exception vérifiée. Par exemple: si le fichier est supprimé ou si l'autorisation de fichier est modifiée par quelqu'un d'autre, il doit être récupéré.

FileNotFoundException est un bon exemple pour comprendre les différences subtiles. FileNotFoundException est levée si le fichier est introuvable. Il y a deux raisons à cette exception. Si le chemin du fichier est défini par le développeur ou par l'utilisateur final via l'interface graphique, il doit s'agir d'une exception non vérifiée. Si le fichier est supprimé par quelqu'un d'autre, il doit s'agir d'une exception vérifiée.

L'exception vérifiée peut être gérée de deux manières. Ceux-ci utilisent try-catch ou propagent l'exception. En cas de propagation d'exception, toutes les méthodes de la pile d'appels seront étroitement couplées en raison de la gestion des exceptions. C'est pourquoi, nous devons utiliser soigneusement l'exception vérifiée.

Dans le cas où vous développez un système d'entreprise en couches, vous devez choisir la plupart du temps l'exception non vérifiée à lancer, mais n'oubliez pas d'utiliser l'exception cochée pour le cas où vous ne pouvez rien faire.

ailhanli
la source
1

Les exceptions cochées sont utiles dans les cas récupérables où vous souhaitez fournir des informations à l'appelant (par exemple, autorisations insuffisantes, fichier introuvable, etc.).

Les exceptions non vérifiées sont rarement utilisées, voire pas du tout, pour informer l'utilisateur ou le programmeur d'erreurs graves ou de conditions inattendues pendant l'exécution. Ne les jetez pas si vous écrivez du code ou des bibliothèques qui seront utilisées par d'autres, car ils ne s'attendent pas à ce que votre logiciel lève des exceptions non contrôlées car le compilateur ne les force pas à être capturés ou déclarés.

David Crow
la source
Je ne suis pas d'accord avec votre affirmation "Les exceptions non vérifiées sont rarement utilisées, voire pas du tout", en fait, cela devrait être opposé! Utilisez des exceptions non vérifiées par défaut lorsque vous concevez votre hiérarchie d'exceptions d'application. Laissez les développeurs décider quand ils veulent gérer l'exception (par exemple, ils ne sont pas obligés de mettre des blocs catch ou des clauses throws s'ils ne savent pas comment les gérer).
user1697575
1

Chaque fois qu'une exception est moins probable, et nous pouvons continuer même après avoir attrapé cela, et nous ne pouvons rien faire pour éviter cette exception, nous pouvons utiliser l'exception vérifiée.

Chaque fois que nous voulons faire quelque chose de significatif lorsqu'une exception particulière se produit et lorsque cette exception est attendue mais pas certaine, nous pouvons utiliser l'exception vérifiée.

Chaque fois qu'une exception navigue dans différentes couches, nous n'avons pas besoin de l'attraper dans chaque couche, dans ce cas, nous pouvons utiliser une exception d'exécution ou une exception d'habillage comme exception non vérifiée.

L'exception d'exécution est utilisée lorsque l'exception est le plus susceptible de se produire, il n'y a aucun moyen d'aller plus loin et rien ne peut être récupéré. Dans ce cas, nous pouvons donc prendre des précautions à l'égard de cette exception. EX: NUllPointerException, ArrayOutofBoundsException. Ce sont plus susceptibles de se produire. Dans ce scénario, nous pouvons prendre des précautions lors du codage pour éviter une telle exception. Sinon, nous devrons écrire des blocs try catch partout.

Des exceptions plus générales peuvent être faites. Non cochées, les moins générales sont vérifiées.

ramu p
la source
1

Je pense que nous pouvons penser à des exemptions de plusieurs questions:

pourquoi l'exemption se produit-elle? Que pouvons-nous faire quand cela se produit

par erreur, un bug. comme une méthode d'objet nul est appelée.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

Ce type d'exception doit être corrigé pendant le test. Sinon, cela interrompt la production et vous avez un bug très élevé qui doit être corrigé immédiatement. Ce type d'exceptions n'a pas besoin d'être vérifié.

par l'entrée de l'extérieur, vous ne pouvez pas contrôler ou faire confiance à la sortie du service externe.

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

Ici, vous devrez peut-être vérifier si le nom est nul si vous voulez continuer quand il est nul, sinon, vous pouvez le laisser tranquille et il s'arrêtera ici et donnera à l'appelant l'exception d'exécution. Ce type d'exceptions n'a pas besoin d'être vérifié.

par exception d'exécution externe, vous ne pouvez pas contrôler ou approuver le service externe.

Ici, vous devrez peut-être intercepter toutes les exceptions de ExternalService si vous souhaitez continuer quand cela se produit, sinon, vous pouvez le laisser seul et il s'arrêtera ici et donnera à l'appelant l'exception d'exécution.

par exception vérifiée de l'extérieur, vous ne pouvez pas contrôler ou faire confiance au service externe.

Ici, vous devrez peut-être intercepter toutes les exceptions de ExternalService si vous souhaitez continuer quand cela se produit, sinon, vous pouvez le laisser seul et il s'arrêtera ici et donnera à l'appelant l'exception d'exécution.

Dans ce cas, devons-nous savoir quel type d'exception s'est produit dans ExternalService? Ça dépend:

  1. si vous pouvez gérer certains types d'exceptions, vous devez les intercepter et les traiter. Pour les autres, faites-les bouillonner.

  2. si vous avez besoin d'un journal ou d'une réponse à l'utilisateur de l'exception spécifique, vous pouvez les attraper. Pour les autres, faites-les bouillonner.

Jacky
la source
0

Je pense que lors de la déclaration d'exception d'application, il doit s'agir d'une exception non vérifiée, c'est-à-dire d'une sous-classe de RuntimeException. La raison en est qu'il n'encombrera pas le code d'application avec la déclaration try-catch et throws sur la méthode. Si votre application utilise Java Api, ce qui génère des exceptions vérifiées qui doivent de toute façon être gérées. Dans d'autres cas, l'application peut lever une exception non vérifiée. Si l'appelant de l'application doit toujours gérer l'exception non vérifiée, cela peut être fait.

Akash Aggarwal
la source
-12

La règle que j'utilise est: ne jamais utiliser d'exceptions non contrôlées! (ou quand vous ne voyez aucun moyen de contourner cela)

Du point de vue du développeur utilisant votre bibliothèque ou de l'utilisateur final utilisant votre bibliothèque / application, il craint vraiment d'être confronté à une application qui se bloque en raison d'une exception non résolue. Et compter sur un fourre-tout n'est pas bon non plus.

De cette façon, l'utilisateur final peut toujours recevoir un message d'erreur, au lieu de la disparition complète de l'application.


la source
1
Vous n'expliquez pas ce que vous pensez être mal avec un fourre-tout pour la plupart des exceptions non vérifiées.
Matthew Flaschen
Entièrement en désaccord avec votre réponse non argumentée: "ne jamais utiliser d'exceptions non
vérifiées