Joshua Bloch dans " Effective Java " disait que
Utilisez les exceptions vérifiées pour les conditions récupérables et les exceptions d'exécution pour les erreurs de programmation (élément 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 considère-t-il une exception vérifiée?
2. RuntimeException est-il une exception non contrôlée?
Voici ma compréhension d'une exception non contrôlé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 aussi être une exception vérifiée? Je peux essayer de récupérer la situation comme ça? Puis-je? (Remarque: ma troisième question est à l'intérieur de la catch
ci-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-ils cela?
public void someMethod throws Exception{
}
Pourquoi laissent-ils l'exception bouillonner? Est-ce que gérer l'erreur plus tôt n'est pas mieux? Pourquoi bouillonner?
6. Devrais-je masquer l'exception exacte ou la masquer avec Exception?
Voici mes lectures
Beaucoup de gens disent que les exceptions vérifiées (c.-à-d. Celles que vous devriez explicitement attraper ou rediffuser) ne devraient pas être utilisées du tout. Ils ont été éliminés en C #, par exemple, et la plupart des langues ne les ont pas. Ainsi, vous pouvez toujours lancer une sous-classe de RuntimeException
(exception non contrôlée)
Cependant, je pense que les exceptions cochées sont utiles - elles sont utilisées lorsque vous voulez forcer l'utilisateur de votre API à penser à la gestion de la situation exceptionnelle (si celle-ci est récupérable). C'est simplement que les exceptions vérifiées sont utilisées de manière excessive dans la plate-forme Java, ce qui incite les gens à les détester.
Voici ma vue étendue sur le sujet .
En ce qui concerne les questions particulières:
Est-ce que la NumberFormatException
considère une exception vérifiée?
Non. NumberFormatException
n'est pas cochée (= est la sous-classe de RuntimeException
). Pourquoi? Je ne sais pas. (mais il aurait dû y avoir une méthode isValidInteger(..)
)
Est-ce que RuntimeException
est une exception non contrôlée?
Oui, exactement.
Que dois-je faire ici?
Cela dépend de l'emplacement de ce code et de ce que vous voulez qu'il se passe. S'il se trouve dans la couche d'interface utilisateur, attrapez-le et affichez un avertissement. si c'est dans la couche service, ne l'attrapez pas du tout, laissez-le bouillonner. Juste n'avalez pas l'exception. Si une exception se produit dans la plupart des cas, vous devez choisir l'un de ceux-ci:
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?
Cela aurait pu être. Mais rien ne vous empêche d'attraper l'exception non contrôlée
Pourquoi les gens ajoutent-ils la classe Exception
dans la clause throws?
Le plus souvent parce que les gens sont paresseux pour décider de ce qu’il faut attraper et de ce qu’il faut renvoyer. Lancer Exception
est une mauvaise pratique et doit être évité.
Hélas, il n’existe pas de règle unique vous permettant de déterminer quand capturer, quand rediffuser, quand utiliser coché et quand utiliser des exceptions non cochées. Je conviens 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 redéfinir une exception à la couche où vous pouvez la gérer.
Que quelque chose soit une "exception vérifiée" n'a rien à voir avec si vous l'attrapez 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 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 majoritaire semble être que cela ne vaut pas les problèmes de conception que cela 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 l'ensemble 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 avez choisi, plutôt que de vous obliger à les traiter avec des méthodes de bas niveau là où elles se produisent à l'origine.
Ce qui précède est-il considéré comme une exception vérifiée? Non Le fait que vous traitiez une exception n'en fait pas un Checked Exception
s'il s'agit d'un RuntimeException
.
Est-ce que RuntimeException
est un unchecked exception
? Oui
Checked Exceptions
sont subclasses
sur Java.lang.Exception
Unchecked Exceptions
sont subclasses
sur Java.lang.RuntimeException
Les appels renvoyant des exceptions vérifiées doivent être placés 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 ces 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 masquer 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'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 de l'envelopper à l'intérieur. Mais, et un gros problème - Jamais jamais obscurcir la cause première sous-jacente. Par exemple, Don't ever
fait 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:
try {
attemptLogin(userCredentials);
} catch (SQLException sqle) {
throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}
Manger à l'extérieur de la cause initiale enterrera la cause réelle au-delà de la récupération est un cauchemar pour les équipes de support de production où tout leur est donné accès aux journaux d'applications et aux messages d'erreur. Bien que ce dernier soit une meilleure conception mais que beaucoup de personnes l’utilisent rarement, les développeurs ne transmettent simplement pas le message sous-jacent à l’appelant. Faites donc une remarque ferme: Always pass on the actual exception
back, qu'il soit encapsulé ou non dans une exception spécifique à une application.
Sur essayer attraper
RuntimeExceptions
RuntimeException
s 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 pouvant entraîner un RuntimeException
. Pour ex:
try {
setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome 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, 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 arrive parfois qu'une telle vérification d'erreur soit coûteuse, telle que la mise en forme numérique, 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.");
}
Dans ce cas, la vérification des erreurs de pré-invocation ne vaut pas la peine, car elle implique essentiellement de dupliquer tout le code de conversion de chaîne en entier dans la méthode parseInt (). Elle est sujette aux erreurs si elle est implémentée par un développeur. Il est donc préférable d’éliminer tout simplement try-catch.
Donc, NullPointerException
et NumberFormatException
sont tous deux RuntimeExceptions
, attraper un NullPointerException
doit être remplacé par un contrôle de type gracieux alors que je recommande d'attraper un NumberFormatException
explicitement pour éviter une éventuelle introduction de code sujette à erreur.
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 on s'attend à ce que la méthode appelant someMethod
attrape l'exception, cette dernière peut être levée. Il suffit de "passe la balle". Un exemple d'utilisation serait si vous voulez 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 à spécifier toutes les exceptions vérifiées non capturées pouvant être levées dans son champ d'application? 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 générer pour 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 générer, pourquoi ne pas spécifier des exceptions d'exécution également?" Les exceptions d'exécution représentent des problèmes résultant d'un problème de programmation. Par conséquent, on ne peut raisonnablement s'attendre à ce que le code client de l'API en répare ou les traite de quelque manière que ce soit. De tels problèmes incluent des exceptions arithmétiques, telles que la division par zéro; des exceptions de pointeur, telles que la tentative d'accès à un objet via une référence null; et des exceptions d'indexation, telles que la tentative d'accès à un élément de tableau via un index trop grand ou trop petit.
Il existe également un élément d'information important dans la 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 .
Le résultat inférieur est IMHO est que vous pouvez attraper n'importe quel RuntimeException
, mais vous n’êtes pas obligé de le faire et, en fait, la mise en œuvre n’est pas obligée de maintenir le même contrôle non vérifié exceptions levées, celles-ci ne faisant pas partie du contrat.
1) Non, une exception NumberFormatException est une exception non contrôlée. Même si vous l'avez attrapé (vous n'êtes pas obligé de le faire) parce que rien n'est fait. En effet, il s’agit d’une sous-classe de IllegalArgumentException
qui est une sous-classe de RuntimeException
.
2) RuntimeException
est la racine de toutes les exceptions non contrôlées. Chaque sous-classe de RuntimeException
est décochée. Toutes les autres exceptions et Throwable
sont vérifiées à l'exception des erreurs (qui relèvent de Throwable
).
3/4) Vous pouvez avertir l'utilisateur qu'il a sélectionné un fichier inexistant et en demander un nouveau. Ou bien, arrêtez d'informer l'utilisateur qu'il a entré quelque chose d'invalide.
5) Lancer et attraper 'Exception'
est une mauvaise pratique. Mais plus généralement, vous pouvez créer d’autres exceptions pour que l’appelant puisse décider de la manière de le gérer. 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. Est-ce que l'appelant veut demander à nouveau ou quitter? Vous renvoyez donc l'Exception dans la chaîne à l'appelant.
Dans de nombreux cas, un unchecked Exception
se produit parce que 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 intercepter, car il existe des moyens plus élégants d'éviter de générer ces exceptions.
Vérifié - Sujet à se produire. Vérifié dans le temps de compilation.
Par exemple, FileOperations
Non vérifié - en raison de données incorrectes. Enregistré dans le 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 à des données erronées et celles-ci ne peuvent en aucun cas être déterminées pendant la compilation.
Les exceptions vérifiées sont vérifiées au moment de la compilation par la machine virtuelle Java et ses relations avec les 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 doit définir un comportement alternatif pour le gérer dans le bloc catch/finally.
Les exceptions non contrôlées sont des erreurs purement de programmation, un calcul erroné, des données nulles ou même des défaillances de la logique applicative pouvant conduire à des exceptions d'exécution. C'est tout à fait correct de gérer/attraper les exceptions non contrôlées dans le code.
Explication tirée de http://coder2design.com/Java-interview-questions/
Pour répondre à la dernière question (les autres semblent avoir répondu de manière approfondie ci-dessus), "Dois-je masquer 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 ce type. Les exceptions que vous déclarez pouvoir émettre par votre méthode font partie du contrat entre votre méthode et l'appelant. Lancer "FileNotFoundException"
signifie qu'il est possible que le nom du fichier ne soit pas valide et que le fichier ne soit pas trouvé; l'appelant devra gérer cela intelligemment. Lancer Exception
signifie "Hey, sh * t arrive. Deal." Ce qui est un 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 du code "normal
" que vous écrirez.
Exceptions d'exécution Les exceptions d'exécution sont appelées exceptions non contrôlées. Toutes les autres exceptions sont des exceptions vérifiées et elles 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 sans capturer l'exception vérifiée quelque part, votre code ne sera pas compilé. C'est pourquoi elles sont appelées 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 jettent des exceptions vérifiées. Vous devrez donc souvent écrire des gestionnaires d'exceptions pour gérer les exceptions générées par des méthodes que vous n'avez pas écrites.
Ma description de favori absolu de la différence entre les exceptions non vérifiées et vérifiées est fournie par l'article de suivi Java Tutorial, " Exceptions non contrôlées - la controverse "(désolé d’obtenir tous les éléments élémentaires sur ce post - mais, hé, les bases sont parfois les meilleures):
Voici la ligne directrice: Si un client peut raisonnablement s'attendre à récupérer 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 contrôlée.
Le cœur de "quel type d'exception à lancer" est sémantique (dans une certaine mesure) et la citation ci-dessus fournit une excellente ligne directrice (par conséquent, je suis toujours époustouflé par l'idée que C # s'est débarrassé des exceptions vérifiées, en particulier comme le prétend Liskov leur utilité).
Le reste devient alors logique: à quelles exceptions le compilateur s'attend-il à ce que je réponde, explicitement? Ceux dont vous attendez que le client récupère.
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 j'estime que cela répond en partie à votre question et complète bien d'autres réponses.
Chaque fois que des exceptions vérifiées sont impliquées, il existe un throws CheckedException
quelque part dans une signature de méthode (CheckedException
pourrait être toute exception vérifiée). Une signature NE LANCE PAS une exception. Lancer des exceptions est un aspect de la mise en œuvre. Les interfaces, les signatures de méthodes, les classes parentes, tout cela ne doit PAS dépendre de leur implémentation. L'utilisation des exceptions vérifiées ici (en fait, le fait que vous deviez déclarer le throws
dans la signature de la méthode) lie vos interfaces de niveau supérieur 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 celles-ci
public class Foo implements IFoo {
@Override
public void foo() {
System.out.println("I don't throw and exception");
}
}
La classe Foo va parfaitement bien. Faisons maintenant un premier essai en 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 classe Bar ne compilera pas. Comme InterruptedException est une exception vérifiée, vous devez soit la capturer (avec une méthode try-catch dans la méthode foo ()), soit déclarer que vous la 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 pouvoir la traiter correctement ailleurs), modifions la signature.
public class Bar implements IFoo {
@Override
public void foo() throws InterruptedException {
throw new InterruptedException();
}
}
Cette classe Bar ne 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 souhaite programmer l'interface IFoo telle que IFoo foo;
, puis de décider de la mise en oeuvre à utiliser, telle que foo = new Bar();
. Si la méthode foo () de Bar ne remplace pas la méthode foo d'IFoo, lorsque je fais foo.foo();
, il n'appelle pas l'implémentation de foo () de Bar.
Pour que public void foo() throws InterruptedException
de Bar remplace _ public void foo()
d'IFoo, je DOIS ajouter throws InterruptedException
à la signature de méthode d'IFoo. Cela posera cependant des problèmes avec ma classe Foo, car la signature de sa méthode foo () diffère de celle de la 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 de Foo foo () déclarait qu'elle lève une exception InterruptedException mais qu'elle ne lève jamais une exception InterruptedException.
Comme vous pouvez le constater (si j’expliquais bien ce travail), le fait de lancer une exception vérifiée, telle que InterruptedException, me force à associer mon interface IFoo à l’une de ses implémentations, ce qui provoque des ravages chez IFoo. autres implémentations!
C'est l'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'envelopper dans une exception non contrôlée et à lever l'exception non contrôlée.
subclasses
de la classe RuntimeException
sont des exceptions non contrôlées.Exception
mais pas RuntimeException
sont considérées comme checked exceptions
.checked exception
. throws
contenant le checked-exception
.Exception
les classes sont définies pour être vérifiées lorsqu'elles sont jugées suffisamment importantes pour être capturées ou déclarées.Je pense que les exceptions cochées sont un bon rappel pour le développeur qui utilise une bibliothèque externe: le code de cette bibliothèque peut mal tourner dans certaines situations exceptionnelles.
En savoir plus sur les exceptions cochées ou non cochées ici http://learnjava.today/2015/11/checked-vs-unchecked-exceptions/
Voici une règle simple qui peut vous aider à décider. Cela est lié à la manière dont les interfaces sont utilisées en Java.
Prenez votre classe et imaginez qu'elle conçoive une interface telle que celle-ci décrive la fonctionnalité de la classe, mais non l'implémentation sous-jacente (une interface devrait l'être). Imaginez peut-être que vous pourriez implémenter la classe d'une autre manière.
Regardez les méthodes de l'interface et considérez les exceptions qu'elles peuvent 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 devrait 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 devrait pas être dans l'interface. Par conséquent, il doit s'agir d'une exception non vérifiée dans votre classe (car les exceptions non vérifiées ne doivent pas apparaître dans la signature d'interface) ou vous devez l'envelopper et la renvoyer en tant qu'exception vérifiée faisant partie de la méthode d'interface.
Pour décider si vous devez emballer et rediffuser, vous devez à nouveau déterminer s'il est judicieux qu'un utilisateur de l'interface soit obligé de gérer immédiatement la condition d'exception, ou si l'exception est si générale qu'il est impossible de rien faire à ce sujet. 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 transporteur pour un sac de conditions d'erreur possibles pouvant également arriver à d'autres méthodes? Si le premier cas, il peut toujours s'agir d'une exception vérifiée, sinon elle devrait être décochée.
En règle générale, vous ne devez pas prévoir de "bouleverser" les exceptions (capture et redistribution). Une exception doit être gérée par l'appelant (dans ce cas, elle est cochée) ou elle doit aller jusqu'à un gestionnaire de haut niveau (dans ce cas, il est plus facile si elle est décochée).
En bref, les exceptions que votre ou les modules ci-dessus sont supposés gérer pendant l'exécution sont appelées exceptions vérifiées. les autres sont des exceptions non vérifiées qui sont soit RuntimeException
ou Error
.
Dans cette vidéo, il explique les exceptions cochées et non cochées en Java:
https://www.youtube.com/watch?v=ue2pOqLaArw
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 application client-serveur et que le client a demandé une ressource qui n'a pas pu être trouvée ou une autre erreur, il est possible que certaines erreurs se soient produites côté serveur lors du traitement du message. demande de l'utilisateur, il incombe au serveur de dire au client pourquoi il n'a pas pu obtenir la chose pour laquelle il a demandé. Par conséquent, pour y parvenir côté serveur, le code est écrit pour lancer l'exception à l'aide de projection mot-clé au lieu d’avaler ou de le manipuler.Si le serveur le gère/l’avale, il n’y aura aucune chance d’indiquer au client que l’erreur est survenue.
Remarque: pour décrire clairement le type d'erreur, nous pouvons créer notre propre objet Exception et le renvoyer au client.
Soulignons simplement que si vous lancez une exception vérifiée dans un code et que la capture présente plusieurs niveaux, vous devez déclarer cette exception dans la signature de chaque méthode entre vous et la capture. Donc, l'encapsulation est cassée car toutes les fonctions dans le chemin de la projection doivent connaître les détails de cette exception.
Ce sont des exceptions vérifiées. Les exceptions non contrôlées sont des sous-classes de RuntimeException. La décision n'est pas de savoir comment les gérer, c'est que votre code les jette. Si vous ne voulez pas que le compilateur vous dise que vous n'avez pas traité d'exception, utilisez une exception non contrôlée (sous-classe de RuntimeException). Ceux-ci devraient être sauvegardés pour des situations que vous ne pouvez pas récupérer, comme des erreurs de mémoire insuffisante, etc.