Question Java: cochée vs explication d'exception non vérifiée


J'ai lu plusieurs messages sur StackOverFlow à propos des exceptions cochées ou non cochées. Honnêtement, je ne sais toujours pas comment les utiliser correctement.

Joshua Bloch dans "Java efficace" dit que

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

Voyons voir 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. Est-ce que ce qui précède est 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 être une exception vérifiée? Je peux essayer de récupérer la situation comme ça? Puis-je? (Note: ma troisième question est à l'intérieur du catch au dessus)

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 cela?

public void someMethod throws Exception{

}

Pourquoi laissent-elles échapper l'exception? La gestion de l'erreur n'est-elle pas plus rapide? Pourquoi éclater?

EDIT: Dois-je bulle l'exception exacte ou le masque en utilisant Exception?

Voici mes lectures

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

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


582
2018-05-24 19:38


origine


Réponses:


Beaucoup de gens disent que les exceptions vérifiées (c'est-à-dire celles que vous devriez 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 langues n'en ont pas. Donc, vous pouvez toujours jeter 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 à réfléchir à la façon de 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.

En ce qui concerne les questions particulières:

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

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

  3. Que devrais-je faire ici?
    Cela dépend où ce code est et ce que vous voulez arriver. Si elle est dans la couche d'interface utilisateur - l'attraper et afficher un avertissement; si c'est dans la couche de 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 en choisir une:

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

  5. Pourquoi les gens ajoutent-ils de la classe Exception dans la clause throws?
    Le plus souvent parce que les gens sont fainéants pour savoir ce qu'il faut attraper et quoi réarranger. Lancement Exceptionest une mauvaise pratique et devrait être évitée.

Hélas, il n'y a pas de règle unique pour vous permettre de déterminer quand attraper, quand renvoyer, quand utiliser checked et quand utiliser des exceptions non contrôlées. Je suis d'accord cela provoque 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 repousser une exception à la couche où vous pouvez le gérer.


389
2018-05-24 19:49



Que quelque chose soit une "exception vérifiée" n'a rien à voir avec le fait que vous l'attrapiez ou que vous fassiez dans le bloc catch. C'est une propriété des classes d'exception. Tout ce qui est une sous-classe de Exception  sauf pour RuntimeException et 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 de la majorité semble être que cela ne vaut pas les problèmes de conception qu'elle crée.

Pourquoi laissent-ils la bulle d'exception   en haut? Isnt erreur de poignée le plus tôt le   meilleur? Pourquoi éclater?

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


205
2018-05-24 19:53



  1. Est-ce que ce qui précède est une exception vérifiée? Non Le fait que vous gérez une exception ne fait pas une exception Checked si c'est une exception RuntimeException.

  2. RuntimeException est une exception non contrôlée? Oui

Les exceptions vérifiées sont des sous-classes de java.lang.Exception Les exceptions non contrôlées sont des sous-classes de java.lang.RuntimeException

Les appels qui lancent des exceptions vérifiées doivent être inclus dans un bloc try {} ou traités dans 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: devrais-je bulle le exact   exception ou masque-t-il 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'exception très générale et peut être utilisée pour envelopper des exceptions internes de bas niveau. Vous feriez mieux de créer une exception personnalisée et d'envelopper à l'intérieur. Mais, et un grand - Ne jamais obscurcir dans la cause racine originale sous-jacente. Par exemple, Dont ever fais suivre -

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

Au lieu de faire ce qui suit:

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

Manger loin des causes profondes d'origine enterre la cause réelle au-delà de la récupération est un cauchemar pour les équipes de soutien à la production où tout ce qu'ils ont accès à est des journaux d'application et des messages d'erreur. Bien que ce dernier est 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 exception retour si oui ou non enveloppé dans une exception spécifique à l'application.

Sur les tentatives d'exécution RuntimeExceptions

RuntimeExceptions en règle générale ne doit pas être essayée. 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 une exception RuntimeException. Par exemple:

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

C'est une mauvaise pratique de programmation. Au lieu de cela, une vérification nulle aurait dû être faite 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 d'erreur est coûteuse, comme le formatage des nombres, considérez 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 de pré-invocation n'en vaut pas la peine, car elle consiste essentiellement à dupliquer tout le code de conversion chaîne-nombre entier à l'intérieur de la méthode parseInt () et est sujette aux erreurs si elle est implémentée par un développeur. Il est donc préférable de ne plus faire d'essais.

Donc NullPointerException et NumberFormatException sont tous les deux RuntimeExceptions, attraper une exception NullPointerException devrait être remplacée par une vérification de null gracieuse alors que je recommande d'attraper une exception NumberFormatException explicitement pour éviter l'introduction possible de code sujet à des erreurs.


61
2018-05-24 19:50



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 l'étend.

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 Si l'on s'attend à ce que la méthode appelle someMethod pour attraper l'exception, ce dernier peut être jeté. Il "passe juste la balle". Un exemple de cette utilisation serait si vous voulez le lancer 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 à spécifier toutes les exceptions vérifiées non interceptées qui peuvent être lancées dans sa portée? Toute exception pouvant être généré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 qu'ils puissent 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: "Si c'est si bon de documenter l'API d'une méthode, y compris les exceptions qu'elle peut lancer, pourquoi ne pas spécifier aussi des exceptions d'exécution?" Les exceptions d'exécution représentent des problèmes résultant d'un problème de programmation et, par conséquent, le code du client d'API ne peut raisonnablement pas être récupéré à partir d'eux ou les traiter de quelque manière que ce soit. Ces problèmes comprennent des exceptions arithmétiques, telles que la division par zéro; des exceptions de pointeur, telles que tenter d'accéder à un objet via une référence null; et les exceptions d'indexation, telles que la tentative d'accès à un élément de tableau via un index trop grand ou trop petit.

Il y a aussi un peu d'information importante dans le Spécification du langage Java:

Les classes d'exception 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.

La ligne de fond à mon humble avis est que vous pouvez attraper RuntimeException, mais vous n'êtes pas obligé de le faire et, en fait, l'implémentation n'est pas nécessaire pour conserver les mêmes exceptions non vérifiées levées, car celles-ci ne font pas partie du contrat.


15
2018-05-24 20:03



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

2) RuntimeException est la racine de toutes les exceptions non vérifiées. Chaque sous-classe de RuntimeException n'est pas cochée. Toutes les autres exceptions et vulnérabilités sont vérifiées à l'exception des erreurs (qui sont sous Throwable).

3/4) Vous pouvez signaler à l'utilisateur qu'il a sélectionné un fichier inexistant et en demander un nouveau. Ou quittez simplement informer l'utilisateur qu'ils ont entré quelque chose de non valide.

5) Lancer et attraper 'Exception' est une mauvaise pratique. Mais plus généralement, vous pouvez lancer d'autres exceptions afin que l'appelant puisse décider comment y faire face. Par exemple, si vous avez écrit une bibliothèque pour gérer la lecture de certaines entrées de fichiers et que votre méthode a été transmise à un fichier inexistant, vous n'avez aucune idée de la manière de gérer cette opération. Est-ce que l'appelant veut demander à nouveau ou quitter? Ainsi, vous renvoyez l'Exception vers l'appelant.

Dans de nombreux cas, une exception non vérifiée se produit car le programmeur n'a pas vérifié les entrées (dans le cas de NumberFormatException dans votre première question). C'est pourquoi il est facultatif de les attraper, car il existe des moyens plus élégants pour éviter de générer ces exceptions.


9
2018-05-24 19:56



Vérifié - Susceptible de se produire. Vérifié dans l'heure de compilation.

Par exemple .. FileOperations

Non vérifié - En raison de données incorrectes. Vérifié en cours 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)

L'exception est due aux mauvaises données et ne peut en aucun cas être déterminée lors de la compilation.


7
2017-07-24 16:58



Les exceptions vérifiées sont vérifiées lors de la compilation par la JVM et sont liées aux ressources (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 devrait définir un comportement alternatif pour gérer cela dans le bloc catch / finally.

Les exceptions non contrôlées sont des erreurs purement programmatiques, un mauvais calcul, des données nulles ou même des échecs dans la logique métier peuvent conduire à des exceptions d'exécution. C'est très bien pour gérer / attraper les exceptions non contrôlées dans le code.

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


5
2017-07-13 13:13



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 que cela 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 CheckedException quelque part dans une signature de méthode (CheckedException pourrait être une exception vérifiée). Une signature ne lance PAS une exception, lancer des exceptions est un aspect de la mise en œuvre. Interfaces, signatures de méthodes, classes parentes, toutes ces choses ne devraient pas dépendre de leurs implémentations. L'utilisation des exceptions vérifiées ici (en fait le fait que vous devez déclarer le throws dans la signature de la méthode) lie vos interfaces de plus haut niveau avec 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 la méthode foo(), comme ceux-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. Maintenant, faisons une première tentative à la classe Bar

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 sera pas compilée. Comme InterruptedException est une exception vérifiée, vous devez le capturer (avec une méthode try-catch inside foo ()) ou déclarer que vous le lancez (en ajoutant throws 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 gérer correctement ailleurs), modifions la signature.

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

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

Pour faire de Bar public void foo() throws InterruptedException remplacer IFoo public void foo() Je dois ajouter throws InterruptedException à la signature de méthode d'IFoo. Ceci, cependant, causera des problèmes avec ma classe Foo, puisque la signature de la méthode foo () diffère de la signature de méthode d'IFoo. De plus, si j'ai ajouté throws InterruptedException à la méthode de Foo foo () j'obtiendrais une autre erreur en déclarant que la méthode de Foo foo () déclare qu'elle lève une exception InterruptedException mais elle ne lève jamais une exception InterruptedException.

Comme vous pouvez le voir (si j'ai fait un travail décent pour expliquer ce genre de 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 dégâts sur IFoo. d'autres implémentations!

C'est une grande raison pour laquelle les exceptions vérifiées sont BAD. En majuscules.

Une solution consiste à capturer l'exception vérifiée, l'inclure dans une exception non contrôlée et à lancer l'exception non vérifiée.


3
2017-08-17 13:30