Comprendre les exceptions vérifiées et non contrôlées en Java


703

Joshua Bloch dans " Effective Java " a déclaré que

Utilisez les exceptions vérifiées pour les conditions récupérables et les exceptions d'exécution pour les erreurs de programmation (article 58 dans la 2e édition)

Voyons si je comprends bien.

Voici ma compréhension d'une exception vérifiée:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Ce qui précède est-il considéré comme une exception vérifiée?

2. RuntimeException est-il une exception non vérifiée?

Voici ma compréhension d'une exception non vérifiée:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Maintenant, le code ci-dessus ne pourrait-il pas également être une exception vérifiée? Je peux essayer de récupérer la situation comme ça? Puis-je? (Remarque: ma 3ème question est à l'intérieur de ce qui catchprécède)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Pourquoi les gens font-ils cela?

public void someMethod throws Exception{

}

Pourquoi laissent-ils l'exception bouillonner? N'est-il pas préférable de gérer l'erreur plus tôt? Pourquoi bouillonner?

6. Dois-je faire remonter l'exception exacte ou la masquer en utilisant Exception?

Voici mes lectures

En Java, quand dois-je créer une exception vérifiée et quand doit-il s'agir d'une exception d'exécution?

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


6
J'ai un excellent exemple d'une exception non vérifiée. J'ai une DataSeriesclasse qui contient des données qui doivent toujours rester dans l'ordre temporel. Il existe une méthode pour ajouter un nouveau DataPointà la fin d'un fichier DataSeries. Si tout mon code fonctionne correctement tout au long du projet, un DataPointne devrait jamais être ajouté à la fin qui a une date antérieure à celle déjà à la fin. Chaque module de l'ensemble du projet est construit avec ce truisme. Cependant, je vérifie cette condition et lève une exception non vérifiée si cela se produit. Pourquoi? Si cela se produit, je veux savoir qui fait cela et y remédier.
Erick Robertson

3
Pour ajouter encore plus de confusion. Beaucoup de gens prônaient les exceptions vérifiées il y a environ 10 ans, mais la vue se tourne de plus en plus vers "les exceptions vérifiées sont mauvaises". (Je ne suis cependant pas d'accord là-dessus)
Kaj

10
Il n'est utile de gérer une exception que lorsque vous avez quelque chose d'utile à faire avec elle, sinon vous devriez laisser l'appelant la gérer. L'enregistrer et prétendre que cela ne s'est pas produit n'est généralement pas utile. Le relancer est inutile. L'encapsulation dans une RuntimeException n'est pas aussi utile que certains le pensent, cela fait simplement que le compilateur cesse de vous aider. (À
mon humble avis

40
Nous devons cesser d'utiliser les termes complètement trompeurs des exceptions vérifiées / non vérifiées . Ils devraient être appelés check-mandat vs chèque-mandat sans exceptions.
Blessed Geek

3
J'ai également pensé qu'abt ur 5ème point public void method_name lève l'exception {} pourquoi certaines personnes font ça?
Maveň

Réponses:


474

Beaucoup de gens disent que les exceptions vérifiées (c'est-à-dire celles que vous devez explicitement attraper ou relancer) ne devraient pas du tout être utilisées. Ils ont été éliminés en C # par exemple, et la plupart des langages n'en ont pas. Vous pouvez donc toujours lancer une sous-classe de RuntimeException(exception non vérifiée)

Cependant, je pense que les exceptions vérifiées sont utiles - elles sont utilisées lorsque vous voulez forcer l'utilisateur de votre API à penser comment gérer la situation exceptionnelle (si elle est récupérable). C'est juste que les exceptions vérifiées sont surutilisées dans la plate-forme Java, ce qui fait que les gens les détestent.

Voici ma vue étendue sur le sujet .

Quant aux questions particulières:

  1. Est -ce la NumberFormatExceptionconsidèrent une exception vérifiée?
    Non NumberFormatExceptionest décoché (= est une sous-classe de RuntimeException). Pourquoi? Je ne sais pas. (mais il aurait dû y avoir une méthode isValidInteger(..))

  2. Est RuntimeExceptionune exception non vérifiée?
    Oui, exactement.

  3. Que dois-je faire ici?
    Cela dépend de l'emplacement de ce code et de ce que vous voulez faire. S'il est dans la couche d'interface utilisateur - attrapez-le et affichez un avertissement; s'il est dans la couche service - ne l'attrapez pas du tout - laissez-le bouillonner. N'avalez pas l'exception. Si une exception se produit dans la plupart des cas, vous devez choisir l'un d'entre eux:

    • connectez-vous et revenez
    • retournez-le (déclarez-le être jeté par la méthode)
    • construire une nouvelle exception en passant l'actuelle dans le constructeur
  4. Maintenant, le code ci-dessus ne pourrait-il pas également être une exception vérifiée? Je peux essayer de récupérer la situation comme ça? Puis-je?
    Ça aurait pu l'être. Mais rien ne vous empêche également d'attraper l'exception non contrôlée

  5. Pourquoi les gens ajoutent-ils de la classe Exceptiondans la clause throws?
    Le plus souvent parce que les gens sont paresseux pour considérer ce qu'il faut attraper et ce qu'il faut repousser. Le lancer Exceptionest une mauvaise pratique et doit être évité.

Hélas, il n'y a pas de règle unique pour vous permettre de déterminer quand attraper, quand ré-lancer, quand utiliser les exceptions cochées et quand utiliser les exceptions non cochées. Je suis d'accord que cela cause beaucoup de confusion et beaucoup de mauvais code. Le principe général est énoncé par Bloch (vous en avez cité une partie). Et le principe général est de renvoyer une exception à la couche où vous pouvez la gérer.


36
En ce qui concerne la levée d'exception, ce n'est pas toujours parce que les gens sont paresseux, il est également courant que vous, lorsque vous implémentez des frameworks, permettez aux utilisateurs du framework de lever n'importe quelle exception. Vous pouvez par exemple vérifier la signature de l'interface Callable dans JSE
Kaj

10
@Kaj - oui, ces choses générales comme Callable, les intercepteurs et autres sont des cas spéciaux. Mais dans la plupart des cas, c'est parce que les gens sont paresseux :)
Bozho

7
re: 3.1 "connectez-vous et revenez" Faites-le judicieusement. C'est très proche de manger ou de se cacher et d'exception. Je ferais cela pour quelque chose qui n'indique pas un problème, qui n'est pas vraiment exceptionnel. Les journaux sont inondés et ignorés trop facilement.
Chris

4
"quand vous voulez forcer l'utilisateur de votre API à penser comment gérer la situation exceptionnelle" - vous ne pouvez forcer personne à penser s'il ne le veut pas. S'ils ne veulent pas réfléchir, ils écriront un mauvais bloc d'exceptions qui ne fait rien du tout, ou pire, supprime ou interfère avec les informations d'erreur critique. C'est pourquoi les exceptions vérifiées sont un échec.
adrianos

3
@adrianos "... vous ne pouvez pas forcer quelqu'un à penser s'il ne veut pas ...." Avec cette ligne de pensée, nous pourrions également supprimer les erreurs de compilation .... Je ne vous cible pas vraiment, j'ai entendu cela l'argument maintes et maintes fois et trouve toujours que c'est la plus mauvaise explication possible pour étiqueter les exceptions vérifiées comme un échec. En guise de remarque, j'ai vu auparavant un tel langage où la compilation (et les erreurs d'exécution également) étaient effectivement rendues impossibles par la conception. Cette route a conduit à des endroits très sombres.
Newtopian

233

Que quelque chose soit une "exception vérifiée" n'a rien à voir avec le fait que vous l'attrapiez ou ce que vous faites dans le bloc catch. C'est une propriété de classes d'exception. Tout ce qui est une sous-classe à l' Exception exception de RuntimeExceptionet ses sous-classes est une exception vérifiée.

Le compilateur Java vous oblige à intercepter les exceptions vérifiées ou à les déclarer dans la signature de la méthode. Il était censé améliorer la sécurité du programme, mais l'opinion majoritaire semble être qu'il ne vaut pas les problèmes de conception qu'il crée.

Pourquoi laissent-ils l'exception bouillonner? N'est-ce pas gérer l'erreur le plus tôt sera le mieux? Pourquoi bouillonner?

Parce que c'est tout le point des exceptions. Sans cette possibilité, vous n'auriez pas besoin d'exceptions. Ils vous permettent de gérer les erreurs au niveau que vous choisissez, plutôt que de vous forcer à les traiter dans des méthodes de bas niveau là où elles se produisent à l'origine.


3
Je vous remercie! Je jette parfois des exceptions de mes méthodes à cause du principe de la merde dans la merde. Si l'un des développeurs de mon équipe souhaite saisir une expression xpath non valide, c'est à lui de gérer l'exception. Dans le cas peu probable, ils interceptent une exception et ne font rien, ils en entendront parler lors de la révision du code.
jeremyjjbrown

12
"Tout ce qui est une sous-classe de Throwable à l'exception de RuntimeException et de ses sous-classes est une exception vérifiée." - Votre déclaration est incorrecte. L'erreur hérite également de Throwable et elle n'est pas cochée.
Bartzilla

8
@JonasEicher: fondamentalement, le principal avantage des exceptions est qu'elles vous permettent de choisir où dans la pile d'appels vous souhaitez gérer les erreurs, ce qui est souvent assez élevé, tout en gardant les couches intermédiaires complètement exemptes d'artefacts de gestion des erreurs. Les exceptions vérifiées détruisent exactement cet avantage. Un autre problème est que la distinction cochée / décochée est liée à la classe des exceptions qui représente également une catégorisation conceptuelle des exceptions - mélangeant deux aspects qui ne sont pas nécessairement liés du tout.
Michael Borgwardt

2
"mais l'opinion majoritaire semble être que cela ne vaut pas les problèmes de conception qu'elle crée." - Citation s'il vous plait?
kervin

3
@ Bartzilla Oui. Pour être complet, comme le dit le javadoc pour Throwable: "Throwable et toute sous-classe de Throwable qui n'est pas également une sous-classe de RuntimeException ou Error sont considérées comme des exceptions vérifiées"
Bart van Heukelom

74
  1. Est-ce que ce qui précède est considéré comme une exception vérifiée? Non Le fait que vous gériez une exception n'en fait pas un Checked Exceptionsi c'est un RuntimeException.

  2. Est RuntimeExceptionun unchecked exception? Oui

Checked Exceptionssont subclassesde java.lang.Exception Unchecked Exceptionssont subclassesdejava.lang.RuntimeException

Les appels générant des exceptions vérifiées doivent être inclus dans un bloc try {} ou traités à un niveau supérieur dans l'appelant de la méthode. Dans ce cas, la méthode actuelle doit déclarer qu'elle lève lesdites exceptions afin que les appelants puissent prendre les dispositions appropriées pour gérer l'exception.

J'espère que cela t'aides.

Q: dois-je faire remonter l'exception exacte ou la masquer en utilisant Exception?

R: Oui, c'est une très bonne question et une considération de conception importante. La classe Exception est une classe d'exceptions très générale et peut être utilisée pour encapsuler des exceptions internes de bas niveau. Vous feriez mieux de créer une exception personnalisée et de l'envelopper. Mais, et un grand - Jamais jamais obscur dans la cause racine d'origine sous-jacente. Par exemple, Don't everfaites ce qui suit -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Faites plutôt ce qui suit:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Ronger la cause racine d'origine enterre la cause réelle au-delà de la récupération est un cauchemar pour les équipes de support de production où tout ce qui leur est accordé est les journaux d'application et les messages d'erreur. Bien que ce dernier soit une meilleure conception, mais beaucoup de gens ne l'utilisent pas souvent parce que les développeurs ne parviennent pas à transmettre le message sous-jacent à l'appelant. Alors, faites une note ferme: Always pass on the actual exceptionrevenez si enveloppé dans une exception spécifique à l'application.

En essayant d'attraper RuntimeExceptions

RuntimeExceptions en règle générale ne doit pas être essayé. Ils signalent généralement une erreur de programmation et doivent être laissés seuls. Au lieu de cela, le programmeur doit vérifier la condition d'erreur avant d'appeler du code qui pourrait entraîner un RuntimeException. Par exemple:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Il s'agit d'une mauvaise pratique de programmation. Au lieu de cela, un contrôle nul aurait dû être fait comme -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Mais il y a des moments où une telle vérification des erreurs coûte cher, comme le formatage des nombres, pensez à ceci -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Ici, la vérification des erreurs avant invocation ne vaut pas la peine, car cela signifie essentiellement de dupliquer tout le code de conversion chaîne en entier dans la méthode parseInt () - et est sujet aux erreurs s'il est implémenté par un développeur. Il est donc préférable de simplement supprimer le try-catch.

Donc, NullPointerExceptionet NumberFormatExceptionsont les deux RuntimeExceptions, attraper un NullPointerExceptiondevrait être remplacé par une vérification nulle gracieuse tandis que je recommande d'attraper NumberFormatExceptionexplicitement un pour éviter l'introduction possible de code sujet aux erreurs.


Je vous remercie. Une autre question lorsque vous faites bouillonner le exception, dois-je faire bouillir l'exception exacte ou la masquer à l'aide Exception. J'écris du code au-dessus d'un code hérité et je fais des Exceptionbulles partout. Je me demande si c'est le bon comportement?
Thang Pham

1
C'est une très bonne et importante question, j'ai modifié ma réponse pour inclure l'explication.
d-live

Merci beaucoup. Serait-il possible pour vous de me montrer le contenu de LoginFailureException(sqle)?
Thang Pham

1
Je n'ai pas de code pour ce genre de choses, je viens de préparer les noms, etc. Si vous voyez java.lang.Exception, il a 4 constructeurs dont deux acceptent java.lang.Throwable. Dans les extraits ci-dessus, j'ai supposé LoginFailureExceptionétendre Exceptionet déclarer un constructeurpublic LoginFailureException(Throwable cause) { super(cause) }
d-live

Meilleure réponse sur le sujet. Je pense que les exceptions d'exécution ne devraient pas être interceptées car ces exceptions se produisent en raison du manque de bonne programmation. Je suis tout à fait d'accord avec la partie "Ronger la cause racine d'origine enfouit la cause réelle au-delà de la récupération est un cauchemar pour les équipes de support de production où tout ce qui leur est donné accès est les journaux d'application et les messages d'erreur.".
huseyin

19

1 . Si vous n'êtes pas sûr d'une exception, vérifiez l'API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Oui, et chaque exception qui le prolonge.

3. Il n'est pas nécessaire d'attraper et de lancer la même exception. Vous pouvez afficher une nouvelle boîte de dialogue de fichier dans ce cas.

4. FileNotFoundException est déjà une exception vérifiée.

5. S'il est prévu que la méthode appelant someMethodpour intercepter l'exception, cette dernière peut être levée. Il "passe juste le ballon". Un exemple de son utilisation serait si vous souhaitez le jeter dans vos propres méthodes privées et gérer l'exception dans votre méthode publique à la place.

Une bonne lecture est le document Oracle lui-même: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Pourquoi les concepteurs ont-ils décidé de forcer une méthode pour spécifier toutes les exceptions vérifiées non capturées qui peuvent être levées dans sa portée? Toute exception pouvant être levée par une méthode fait partie de l'interface de programmation publique de la méthode. Ceux qui appellent une méthode doivent connaître les exceptions qu'une méthode peut lancer afin de pouvoir décider quoi faire à leur sujet. Ces exceptions font autant partie de l'interface de programmation de cette méthode que ses paramètres et sa valeur de retour.

La question suivante pourrait être: "S'il est si bon de documenter l'API d'une méthode, y compris les exceptions qu'elle peut lever, pourquoi ne pas spécifier également des exceptions d'exécution?" Les exceptions d'exécution représentent des problèmes qui sont le résultat d'un problème de programmation, et en tant que tel, le code client API ne peut raisonnablement pas s'attendre à en récupérer ou à les gérer de quelque manière que ce soit. Ces problèmes incluent les exceptions arithmétiques, telles que la division par zéro; les exceptions de pointeur, telles que la tentative d'accès à un objet via une référence nulle; et l'indexation des exceptions, telles que la tentative d'accès à un élément de tableau via un index trop grand ou trop petit.

La spécification du langage Java contient également des informations importantes :

Les classes d'exceptions vérifiées nommées dans la clause throws font partie du contrat entre l'implémenteur et l'utilisateur de la méthode ou du constructeur .

L'IMHO en bout de ligne est que vous pouvez en attraper RuntimeException, mais vous n'êtes pas obligé de le faire et, en fait, la mise en œuvre n'est pas requise pour maintenir les mêmes exceptions non vérifiées levées, car celles-ci ne font pas partie du contrat.


Je vous remercie. Une autre question lorsque vous faites bouillonner le exception, dois-je faire bouillir l'exception exacte ou la masquer à l'aide Exception. J'écris du code au-dessus d'un code hérité et je fais des Exceptionbulles partout. Je me demande si c'est le bon comportement?
Thang Pham

1
@Harry, je laisserai les gens avec plus de connaissances que moi répondre à: stackoverflow.com/questions/409563/…
Aleadam

10

1) Non, une exception NumberFormatException est une exception non vérifiée. Même si vous l'avez attrapé (vous n'êtes pas obligé de le faire) parce qu'il n'est pas contrôlé. C'est parce que c'est une sous-classe IllegalArgumentExceptiondont est une sous-classe de RuntimeException.

2) RuntimeExceptionest la racine de toutes les exceptions non contrôlées. Chaque sous-classe de RuntimeExceptionn'est pas cochée. Toutes les autres exceptions et Throwablesont vérifiées à l'exception des erreurs (qui figurent sous Throwable).

3/4) Vous pouvez alerter l'utilisateur qu'il a choisi un fichier inexistant et en demander un nouveau. Ou tout simplement arrêter d'informer l'utilisateur qu'il a entré quelque chose de non valide.

5) Lancer et attraper 'Exception'est une mauvaise pratique. Mais plus généralement, vous pouvez lever d'autres exceptions pour que l'appelant puisse décider comment y faire face. Par exemple, si vous avez écrit une bibliothèque pour gérer la lecture d'une entrée de fichier et que votre méthode a reçu un fichier inexistant, vous ne savez pas comment gérer cela. L'appelant veut-il demander à nouveau ou quitter? Vous renvoyez donc l'exception dans la chaîne à l'appelant.

Dans de nombreux cas, un unchecked Exceptionse produit parce que le programmeur n'a pas vérifié les entrées (dans le cas de NumberFormatExceptionvotre première question). C'est pourquoi il est facultatif de les attraper, car il existe des moyens plus élégants d'éviter de générer ces exceptions.


Je vous remercie. Une autre question lorsque vous faites bouillonner le exception, dois-je faire bouillir l'exception exacte ou la masquer à l'aide Exception. J'écris du code au-dessus d'un code hérité et je fais des Exceptionbulles partout. Je me demande si c'est le bon comportement?
Thang Pham

Vous pouvez soit demander à votre méthode de lancer également Exception (ce qui n'est pas idéal). Ou attrapez une exception et lancez une meilleure exception (comme IOException ou quelque chose). Toutes les exceptions peuvent prendre une exception dans leur constructeur comme «cause», vous devez donc l'utiliser.
dontocsata

8

Vérifié - susceptible de se produire. Vérifié au moment de la compilation.

Par exemple, FileOperations

Non vérifié - en raison de données incorrectes. Vérifié en temps d'exécution.

Par exemple..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Ici, l'exception est due à de mauvaises données et ne peut en aucun cas être déterminée pendant la compilation.


6

Les exceptions vérifiées sont vérifiées au moment de la compilation par la JVM et ses ressources associées (fichiers / db / stream / socket, etc.). Le motif de l'exception vérifiée est qu'au moment de la compilation, si les ressources ne sont pas disponibles, l'application doit définir un comportement alternatif pour gérer cela dans le bloc catch / finally.

Les exceptions non vérifiées sont des erreurs purement programmatiques, un mauvais calcul, des données nulles ou même des échecs dans la logique métier peuvent entraîner des exceptions d'exécution. C'est absolument bien pour gérer / intercepter les exceptions non contrôlées dans le code.

Explication tirée de http://coder2design.com/java-interview-questions/


5

Ma description préférée absolue de la différence entre les exceptions non vérifiées et vérifiées est fournie par l'article de la piste Java Tutorial, " Unchecked Exceptions - the Controversy " (désolé d'avoir tout élémentaire sur ce post - mais, hé, les bases sont parfois les meilleures):

Voici la ligne directrice: si l'on peut raisonnablement s'attendre à ce qu'un client se remette d'une exception, faites-en une exception vérifiée. Si un client ne peut rien faire pour récupérer de l'exception, faites-en une exception non cochée

Le cœur de "quel type d'exception à lever" est sémantique (dans une certaine mesure) et la citation ci-dessus fournit et une excellente ligne directrice (par conséquent, je suis toujours époustouflé par la notion que C # s'est débarrassé des exceptions vérifiées - en particulier comme le soutient Liskov pour leur utilité).

Le reste devient alors logique: à quelles exceptions le compilateur s'attend-il que je réponde, explicitement? Ceux dont vous attendez que le client se rétablisse.


5

Pour répondre à la dernière question (les autres semblent avoir répondu à fond ci-dessus), "Dois-je faire remonter l'exception exacte ou la masquer en utilisant Exception?"

Je suppose que vous voulez dire quelque chose comme ça:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Non, déclarez toujours l' exception la plus précise possible, ou une liste de ces exceptions. Les exceptions que vous déclarez que votre méthode est capable de lancer font partie du contrat entre votre méthode et l'appelant. Le lancement "FileNotFoundException"signifie qu'il est possible que le nom de fichier ne soit pas valide et que le fichier ne soit pas trouvé; l'appelant devra gérer cela intelligemment. Lancer Exceptionsignifie "Hé, ça se passe. Deal." Ce qui est très pauvre API.

Dans les commentaires sur le premier article, il y a quelques exemples où "jette Exception" est une déclaration valide et raisonnable, mais ce n'est pas le cas pour la plupart des " normal" codes que vous écrirez jamais.


Exactement, intégrez votre déclaration d'exception de chèque à la documentation de votre code et aidez la personne qui utilise votre logiciel.
Salvador Valence

5

Exceptions d'exécution : les exceptions d'exécution sont appelées exceptions non vérifiées. Toutes les autres exceptions sont des exceptions vérifiées et ne dérivent pas de java.lang.RuntimeException.

Exceptions vérifiées: Une exception vérifiée doit être interceptée quelque part dans votre code. Si vous appelez une méthode qui lève une exception vérifiée mais que vous n'attrapez pas l'exception vérifiée quelque part, votre code ne sera pas compilé. C'est pourquoi on les appelle des exceptions vérifiées: le compilateur vérifie qu'elles sont gérées ou déclarées.

Un certain nombre de méthodes de l'API Java génèrent des exceptions vérifiées, vous écrivez donc souvent des gestionnaires d'exceptions pour gérer les exceptions générées par des méthodes que vous n'avez pas écrites.


3

Pourquoi laissent-ils l'exception bouillonner? N'est-il pas préférable de gérer l'erreur plus tôt? Pourquoi bouillonner?

Par exemple, disons que vous avez une application client-serveur et que le client a fait une demande pour une ressource qui n'a pas pu être découverte ou pour une autre erreur, certaines peuvent être survenues côté serveur lors du traitement de la demande de l'utilisateur, alors c'est le devoir du serveur pour dire au client pourquoi il n'a pas pu obtenir la chose qu'il a demandée, donc pour y parvenir côté serveur, du code est écrit pour lever l'exception en utilisant throw mot-clé au lieu d'avaler ou de le gérer. si le serveur le gère / swallow il, alors il n'y aura aucune chance d'informer le client que quelle erreur s'est produite.

Remarque: Pour donner une description claire de ce que le type d'erreur s'est produit, nous pouvons créer notre propre objet Exception et le lancer au client.


Bon point. Ce que cela signifie, c'est de le propulser jusqu'à la couche la plus responsable qui contrôle le flux logique et supervise la logique métier de l'application. Il serait impossible, par exemple, pour la couche de base de données de communiquer au client qu'un élément critique manque ou ne répond pas. Quand il bouillonne jusqu'à la couche supérieure du serveur, il est simple de rafraîchir la vue du client avec un message d'erreur critique.
Salvador Valence


3

Je veux juste ajouter un raisonnement pour ne pas utiliser du tout les exceptions vérifiées. Ce n'est pas une réponse complète, mais je pense qu'elle répond à une partie de votre question et complète de nombreuses autres réponses.

Chaque fois que des exceptions vérifiées sont impliquées, il y a throws CheckedExceptionquelque part dans une signature de méthode (il CheckedExceptionpeut s'agir de toute exception vérifiée). Une signature ne lève PAS d'exception, la levée d'exceptions est un aspect de l'implémentation. Interfaces, signatures de méthodes, classes parentes, toutes ces choses ne devraient PAS dépendre de leurs implémentations. L'utilisation d'exceptions vérifiées ici (en fait le fait que vous devez déclarer la throwsdans la signature de méthode) lie vos interfaces de niveau supérieur à vos implémentations de ces interfaces.

Permettez-moi de vous montrer un exemple.

Ayons une interface agréable et propre comme celle-ci

public interface IFoo {
    public void foo();
}

Maintenant, nous pouvons écrire de nombreuses implémentations de méthode foo(), comme celles-ci

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

La classe Foo est parfaitement bien. Faisons maintenant un premier essai au bar de classe

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Cette barre de classe ne se compilera pas. Comme InterruptedException est une exception vérifiée, vous devez soit la capturer (avec une méthode try-catch à l'intérieur de foo ()), soit déclarer que vous la lancez (en ajoutantthrows InterruptedException à la signature de la méthode). Comme je ne veux pas capturer cette exception ici (je veux qu'elle se propage vers le haut pour que je puisse la traiter correctement ailleurs), modifions la signature.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Cette barre de classe ne se compilera pas non plus! La méthode foo () de Bar ne remplace PAS la méthode foo () d'IFoo car leurs signatures sont différentes. Je pourrais supprimer l'annotation @Override, mais je veux programmer contre l'interface IFoo commeIFoo foo; et plus tard décider de l'implémentation que je veux utiliser, comme foo = new Bar();. Si la méthode foo () de Bar ne remplace pas la méthode foo d'IFoo, quand je le ferai, foo.foo();elle n'appellera pas l'implémentation de foo () par Bar.

Pour faire public void foo() throws InterruptedExceptionpasser outre le IFoo de Bar, public void foo()je DOIS ajouterthrows InterruptedException DOIS à la signature de la méthode IFoo. Cependant, cela causera des problèmes avec ma classe Foo, car sa signature de méthode foo () diffère de la signature de méthode IFoo. De plus, si j'ajoutais throws InterruptedExceptionà la méthode foo () de Foo, j'obtiendrais une autre erreur indiquant que la méthode foo () de Foo déclare qu'elle lève une InterruptedException mais qu'elle ne lève jamais une InterruptedException.

Comme vous pouvez le voir (si j'ai fait un travail décent pour expliquer ces choses), le fait que je lève une exception vérifiée comme InterruptedException me force à lier mon interface IFoo à l'une de ses implémentations, ce qui provoque des ravages sur IFoo. autres implémentations!

C'est une des principales raisons pour lesquelles les exceptions vérifiées sont MAUVAISES. En majuscules.

Une solution consiste à capturer l'exception vérifiée, à l'encapsuler dans une exception non vérifiée et à lever l'exception non vérifiée.


2
Oui, c'est mauvais parce que tu as dit que tu ne voulais pas l'attraper. Mais pour éviter d'affecter la signature d'IFOO, vous devrez le faire. Je préfère faire cela et passer au lieu de rééquilibrer toutes mes signatures d'interfaces afin d'éviter d'attraper une exception (juste parce que les exceptions sont MAUVAISES).
Salvador Valence

Oui je suis d'accord. J'étais un peu flou sur quelque chose. Je veux qu'une exception se propage, donc je peux m'en occuper ailleurs. Une solution consiste à intercepter l'exception InterruptedException et à lever une exception non contrôlée. c'est-à-dire que nous évitons les exceptions vérifiées et contournons les exceptions non vérifiées (même si elles n'ont de sens qu'en tant que wrapper)
Blueriver

"Ceci, cependant, causera des problèmes avec ma classe Foo, car c'est la signature de la méthode foo () qui diffère de la signature de la méthode IFoo". Je viens de tester votre idée, et il est possible de compiler même si nous ajoutons throws InterruptedExceptionà la signature de la méthode IFoo sans rien lancer dans aucune implémentation. Cela ne pose donc pas vraiment de problème. Si dans une interface vous effectuez chaque levée de signature de méthode Exception, cela donne simplement à une implémentation le choix de lever ou de ne pas lever une exception (toute exception, comme Exceptionencapsule toutes les exceptions).
Flyout91

Cependant, j'admets que cela peut être déroutant car lorsque vous implémentez une telle interface et cliquez sur quelque chose comme "Ajouter des méthodes non implémentées", elles seront automatiquement créées avec la throw Exceptionclause dans leur signature, même si votre implémentation ne lève rien ou peut être une exception plus spécifique. Mais j'ai toujours l'impression que c'est une bonne pratique de toujours lancer Exception pour une méthode d'interface car, encore une fois, cela donne à l'utilisateur le choix de lancer ou de ne rien lancer.
Flyout91

Cela manque le point entier. Le but d'une interface est de déclarer le contrat dont un client a besoin pour être satisfait. Cela peut inclure des scénarios de défaillance qu'il est capable de gérer. Lorsqu'une implémentation rencontre une erreur, elle doit mapper cette erreur à l'échec abstrait approprié déclaré par l'interface client.
erickson

3
  • Java distingue deux catégories d'exceptions (cochée et décochée).
  • Java applique une capture ou une exigence déclarée pour les exceptions vérifiées.
  • Le type d'une exception détermine si une exception est cochée ou décochée.
  • Tous les types d'exceptions qui sont directs ou indirects subclassesde classe RuntimeException sont des exceptions non vérifiées.
  • Toutes les classes qui héritent de la classe Exceptionmais pas RuntimeExceptionsont considérées commechecked exceptions .
  • Les classes qui héritent de la classe Error sont considérées comme non vérifiées.
  • Le compilateur vérifie chaque appel de méthode et chaque décélération pour déterminer si la méthode est lancée checked exception.
    • Si c'est le cas, le compilateur s'assure que l'exception est interceptée ou déclarée dans une clause throws.
  • Pour satisfaire la partie declare de l'exigence catch-or-declare, la méthode qui génère l'exception doit fournir une throwsclause contenant le checked-exception.
  • Exception les classes sont définies pour être vérifiées lorsqu'elles sont considérées comme suffisamment importantes pour être capturées ou déclarées.

2

Voici une règle simple qui peut vous aider à décider. Elle est liée à la façon dont les interfaces sont utilisées en Java.

Prenez votre classe et imaginez concevoir une interface pour celle-ci de telle sorte que l'interface décrive les fonctionnalités de la classe mais aucune de l'implémentation sous-jacente (comme une interface devrait le faire). Imaginez peut-être que vous pourriez implémenter la classe d'une autre manière.

Examinez les méthodes de l'interface et considérez les exceptions qu'elles pourraient générer:

Si une exception peut être levée par une méthode, quelle que soit l'implémentation sous-jacente (en d'autres termes, elle décrit uniquement la fonctionnalité), il doit probablement s'agir d'une exception vérifiée dans l'interface.

Si une exception est provoquée par l'implémentation sous-jacente, elle ne doit pas se trouver dans l'interface. Par conséquent, il doit s'agir soit d'une exception non vérifiée dans votre classe (car les exceptions non vérifiées n'ont pas besoin d'apparaître dans la signature d'interface), soit vous devez l'encapsuler et la renvoyer en tant qu'exception vérifiée faisant partie de la méthode d'interface.

Pour décider si vous devez encapsuler et relancer, vous devez à nouveau déterminer s'il est logique qu'un utilisateur de l'interface doive gérer la condition d'exception immédiatement, ou si l'exception est si générale que vous ne pouvez rien y faire et qu'elle devrait propager la pile. L'exception encapsulée a-t-elle un sens lorsqu'elle est exprimée en tant que fonctionnalité de la nouvelle interface que vous définissez ou s'agit-il simplement d'un support pour un ensemble de conditions d'erreur possibles qui pourraient également arriver à d'autres méthodes? S'il s'agit de la première, il peut toujours s'agir d'une exception vérifiée, sinon elle doit être décochée.

Vous ne devriez généralement pas prévoir d'exceptions "bulle-up" (capture et retour). Soit une exception doit être gérée par l'appelant (auquel cas elle est vérifiée), soit elle doit aller jusqu'au gestionnaire de haut niveau (auquel cas elle est plus facile si elle n'est pas cochée).


2

Juste pour souligner que si vous lancez une exception vérifiée dans un code et que le catch est à quelques niveaux au-dessus, vous devez déclarer l'exception dans la signature de chaque méthode entre vous et le catch. Ainsi, l'encapsulation est interrompue car toutes les fonctions du chemin de lancement doivent connaître les détails de cette exception.


2

En bref, les exceptions que votre module ou les modules ci-dessus sont censés gérer pendant l'exécution sont appelées exceptions vérifiées; d'autres sont des exceptions non vérifiées qui sont soit RuntimeExceptionou Error.

Dans cette vidéo, il explique les exceptions vérifiées et non vérifiées en Java:
https://www.youtube.com/watch?v=ue2pOqLaArw


1

Toutes ces exceptions sont vérifiées. Les exceptions non vérifiées sont des sous-classes de RuntimeException. La décision n'est pas de savoir comment les gérer, c'est si votre code les jette. Si vous ne voulez pas que le compilateur vous dise que vous n'avez pas géré d'exception, vous utilisez une exception non vérifiée (sous-classe de RuntimeException). Ceux-ci doivent être enregistrés pour les situations que vous ne pouvez pas récupérer, comme les erreurs de mémoire insuffisante, etc.


euh. si NumberFormatException est une exception vérifiée, comme vous le dites, n'est-ce pas en contradiction avec le fait qu'elle est héritée de RuntimeException ?
eis

Désolé, je n'étais pas très clair. Je faisais référence à FileNotFoundException et non à NumberFormatException. Sur la base de ses # 2 et # 4, il semblait qu'il pensait que Checked vs Unchecked était basé sur la façon dont vous avez géré l'exception après l'avoir détectée. Pas comment cela a été défini.
mamboking

-1

Si quelqu'un se soucie d'une autre preuve pour ne pas aimer les exceptions vérifiées, consultez les premiers paragraphes de la bibliothèque JSON populaire:

"Bien qu'il s'agisse d'une exception vérifiée, elle est rarement récupérable. La plupart des appelants doivent simplement envelopper cette exception dans une exception non vérifiée et relancer:"

Alors, pourquoi diable quelqu'un ferait-il que les développeurs continuent de vérifier l'exception, si nous devions "simplement envelopper" à la place? lol

http://developer.android.com/reference/org/json/JSONException.html


4
Parce que ce n'est que la plupart des appelants, pas tous les appelants, qui doivent boucler et relancer. Le fait que l'exception soit vérifiée signifie que l'appelant doit se demander s'il s'agit de "la plupart" des appelants ou de la minorité qui peut et doit gérer l'exception.
Warren Dew

1
Si vous aimez vérifier les erreurs pour chaque appel que vous effectuez, "revenez" à C. Les exceptions sont un moyen de séparer l'exécution normale d'un programme d'une anomalie, sans polluer votre code. Les exceptions garantissent que vous ne pouvez pas ignorer une erreur silencieusement à un certain niveau .
Slawomir

-1

Exceptions vérifiées :

  • Les exceptions qui sont vérifiées par le compilateur pour la bonne exécution du programme au moment de l'exécution sont appelées Exception vérifiée.

  • Ceux-ci se produisent au moment de la compilation.

  • Si ceux-ci ne sont pas traités correctement, ils donneront une erreur de temps de compilation (pas d'exception).
  • Toutes les sous-classes de la classe Exception, à l'exception de RuntimeException, sont des exceptions vérifiées.

    Exemple hypothétique - Supposons que vous quittiez votre maison pour l'examen, mais si vous vérifiez si vous avez pris votre ticket d'entrée à la maison (heure de compilation), il n'y aura aucun problème à Exam Hall (exécution).

Exception non vérifiée :

  • Les exceptions qui ne sont pas vérifiées par le compilateur sont appelées exceptions non vérifiées.

  • Ceux-ci se produisent lors de l'exécution.

  • Si ces exceptions ne sont pas gérées correctement, elles ne donnent pas d'erreur de temps de compilation. Mais le programme sera arrêté prématurément au moment de l'exécution.

  • Toutes les sous-classes de RunTimeException et Error sont des exceptions non vérifiées.

    Exemple hypothétique - Supposons que vous soyez dans votre salle d'examen mais que votre école a eu un accident d'incendie (signifie à l'exécution) où vous ne pouvez rien faire à ce moment-là mais des précautions peuvent être prises avant (temps de compilation).


-2

Toutes les exceptions doivent être vérifiées.

  1. Les exceptions non vérifiées sont des gotos sans restriction. Et les gotos sans restriction sont considérés comme une mauvaise chose.

  2. Les exceptions non vérifiées interrompent l'encapsulation. Pour les traiter correctement, toutes les fonctions de l'arborescence d'appels entre le lanceur et le receveur doivent être connues pour éviter les bugs.

  3. Les exceptions sont des erreurs dans la fonction qui les lance, mais pas des erreurs dans la fonction qui les traite. Le but des exceptions est de donner au programme une seconde chance en différant la décision de savoir s'il s'agit d'une erreur ou non dans un autre contexte. Ce n'est que dans l'autre contexte que la bonne décision peut être prise.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.