J'étais en train de parcourir le livre SCJP 6 de Kathe sierra et je suis tombé sur ces explications de lancer des exceptions dans une méthode remplacée. Je n'ai pas du tout compris. Quelqu'un peut-il me l'expliquer?
La méthode de remplacement ne doit PAS lancer d'exceptions vérifiées qui sont nouvelles ou plus larges que celles déclarées par la méthode remplacée. Par exemple, une méthode qui déclare une FileNotFoundException ne peut pas être remplacée par une méthode qui déclare une SQLException, Exception ou toute autre exception non d'exécution, sauf s'il s'agit d'une sous-classe de FileNotFoundException.
Réponses:
Cela signifie que si une méthode déclare lever une exception donnée, la méthode de substitution dans une sous-classe ne peut déclarer que lever cette exception ou sa sous-classe. Par exemple:
SocketException extends IOException
, maisSQLException
pas.C'est à cause du polymorphisme:
Si vous
B
aviez décidé de lancerSQLException
, alors le compilateur ne pourrait pas vous forcer à l'attraper, car vous faites référence à l'instance deB
par sa superclasse -A
. D'un autre côté, toute sous-classe deIOException
sera gérée par des clauses (catch ou throws) qui gèrentIOException
La règle selon laquelle vous devez pouvoir faire référence aux objets par leur superclasse est le principe de substitution de Liskov.
Étant donné que les exceptions non contrôlées peuvent être lancées n'importe où, elles ne sont pas soumises à cette règle. Vous pouvez ajouter une exception non vérifiée à la clause throws en tant que forme de documentation si vous le souhaitez, mais le compilateur n'applique rien à ce sujet.
la source
@Override public void foo() {...}
c'est légal.La méthode de substitution PEUT lever toute exception non vérifiée (à l'exécution), que la méthode remplacée déclare ou non l'exception
Exemple:
la source
À mon avis, c'est un échec dans la conception de la syntaxe Java. Le polymorphisme ne devrait pas limiter l'utilisation de la gestion des exceptions. En fait, les autres langages informatiques ne le font pas (C #).
De plus, une méthode est surchargée dans une sous-classe plus spécialisée afin qu'elle soit plus complexe et, pour cette raison, plus susceptible de lancer de nouvelles exceptions.
la source
Je donne cette réponse ici à l'ancienne question car aucune réponse ne dit que la méthode de substitution ne peut rien jeter, voici à nouveau ce que la méthode de substitution peut lancer:
1) lancer la même exception
2) lancer la sous-classe de l'exception levée de la méthode surchargée
3) ne rien jeter.
4) Il n'est pas nécessaire d'avoir des exceptions RuntimeExceptions dans les lancers.
Il peut y avoir des exceptions Runtime dans les lancers ou non, le compilateur ne s'en plaindra pas. Les exceptions d'exécution ne sont pas des exceptions vérifiées. Seules les exceptions cochées doivent apparaître dans les lancers si elles ne sont pas capturées.
la source
Pour illustrer cela, considérez:
Supposons que vous écriviez alors:
Cela vous donnera une erreur de compilation, car r.close () lève une IOException, qui est plus large que FileNotFoundException.
Pour résoudre ce problème, si vous écrivez:
Vous obtiendrez une erreur de compilation différente, car vous implémentez l'opération perform (...), mais en lançant une exception non incluse dans la définition de la méthode par l'interface.
Pourquoi est-ce important? Eh bien, un consommateur de l'interface peut avoir:
Si l'exception IOException a été autorisée à être levée, le code du client n'est plus correct.
Notez que vous pouvez éviter ce type de problème si vous utilisez des exceptions non vérifiées. (Je ne vous suggère pas de faire ou non, c'est une question philosophique)
la source
Prenons une question d'entrevue. Il existe une méthode qui lève NullPointerException dans la superclasse. Pouvons-nous le remplacer par une méthode qui lève RuntimeException?
Pour répondre à cette question, indiquez-nous ce qu'est une exception non cochée et cochée.
Les exceptions vérifiées doivent être explicitement interceptées ou propagées comme décrit dans Gestion des exceptions try-catch-finally de base. Les exceptions non cochées n'ont pas cette exigence. Ils ne doivent pas être attrapés ou déclarés jetés.
Les exceptions vérifiées dans Java étendent la classe java.lang.Exception. Les exceptions non vérifiées étendent l'exception java.lang.RuntimeException.
public class NullPointerException étend RuntimeException
Les exceptions non vérifiées étendent l'exception java.lang.RuntimeException. C'est pourquoi NullPointerException est une exception Uncheked.
Prenons un exemple: Exemple 1:
Le programme se compilera avec succès. Exemple 2:
Le programme sera également compilé avec succès. Par conséquent, il est évident que rien ne se passe en cas d'exceptions non contrôlées. Voyons maintenant ce qui se passe en cas d'exceptions vérifiées. Exemple 3: Lorsque la classe de base et la classe enfant lèvent toutes deux une exception vérifiée
Le programme se compilera avec succès. Exemple 4: lorsque la méthode de classe enfant lève une exception à la vérification de la bordure par rapport à la même méthode de la classe de base.
Le programme échouera à se compiler. Nous devons donc faire attention lorsque nous utilisons des exceptions Checked.
la source
disons que vous avez une super classe A avec la méthode M1 throwin E1 et la classe B dérivant de A avec la méthode M2 écrasant M1. M2 ne peut rien lancer de DIFFÉRENT ou DE MOINS SPÉCIALISÉ que E1.
En raison du polymorphisme, le client utilisant la classe A devrait être capable de traiter B comme s'il s'agissait de A. Inharitance ===> Is-a (B is-a A). Que se passe-t-il si ce code traitant de la classe A gère l'exception E1, car M1 déclare qu'il lève cette exception vérifiée, mais qu'un type d'exception différent a été levé? Si M1 lançait IOException, M2 pourrait bien lancer FileNotFoundException, car il s'agit d'une IOException. Les clients de A pourraient gérer cela sans problème. Si l'exception lancée était plus large, les clients de A n'auraient aucune chance de le savoir et n'auraient donc aucune chance de l'attraper.
la source
Eh bien java.lang.Exception étend java.lang.Throwable. java.io.FileNotFoundException étend java.lang.Exception. Donc, si une méthode lance java.io.FileNotFoundException, alors dans la méthode override, vous ne pouvez rien lancer plus haut dans la hiérarchie que FileNotFoundException, par exemple vous ne pouvez pas lancer java.lang.Exception. Vous pouvez cependant lancer une sous-classe de FileNotFoundException. Cependant, vous seriez obligé de gérer l'exception FileNotFoundException dans la méthode overriden. Apportez du code et essayez-le!
Les règles sont là pour que vous ne perdiez pas la déclaration throws d'origine en élargissant la spécificité, car le polymorphisme signifie que vous pouvez invoquer la méthode overriden sur la superclasse.
la source
La méthode de remplacement ne doit PAS lancer d'exceptions vérifiées qui sont nouvelles ou plus larges que celles déclarées par la méthode remplacée.
Exemple:
la source
La méthode de remplacement ne doit PAS lancer d'exceptions vérifiées qui sont nouvelles ou plus larges que celles déclarées par la méthode remplacée.
Cela signifie simplement que lorsque vous remplacez une méthode existante, l'exception que cette méthode surchargée lève doit être soit la même exception que celle levée par la méthode d'origine, soit l'une de ses sous-classes .
Notez que la vérification de la gestion de toutes les exceptions vérifiées est effectuée au moment de la compilation et non au moment de l'exécution. Ainsi, au moment de la compilation, le compilateur Java vérifie le type d'exception que la méthode surchargée lève. Étant donné que la méthode remplacée sera exécutée ne peut être décidée qu'au moment de l'exécution, nous ne pouvons pas savoir quel type d'exception nous devons intercepter.
Exemple
Disons que nous avons la classe
A
et sa sous-classeB
.A
a méthodem1
et classeB
a remplacé cette méthode (appelons-lam2
pour éviter toute confusion ..). Disons maintenant lesm1
lancersE1
et lesm2
lancersE2
, ce qui estE1
la superclasse de. Maintenant, nous écrivons le morceau de code suivant:Notez que ce
m1
n'est rien d'autre qu'un appel àm2
(encore une fois, les signatures de méthode sont les mêmes dans les méthodes surchargées donc ne vous méprenez pas avecm1
etm2
.. elles sont juste à différencier dans cet exemple ... elles ont toutes les deux la même signature). Mais au moment de la compilation, tout ce que fait le compilateur Java est d'aller au type de référence (ClassA
dans ce cas) vérifie la méthode si elle est présente et s'attend à ce que le programmeur la gère. Alors évidemment, vous lancerez ou attraperezE1
. Maintenant, au moment de l'exécution, si la méthode surchargée lanceE2
, qui estE1
la superclasse, alors ... eh bien, c'est très faux (pour la même raison que nous ne pouvons pas direB myBObj = new A()
). Par conséquent, Java ne le permet pas. Les exceptions non contrôlées levées par la méthode surchargée doivent être identiques, sous-classes ou inexistantes.la source
Pour comprendre cela, considérons un exemple où nous avons une classe
Mammal
qui définit unereadAndGet
méthode qui lit un fichier, effectue une opération dessus et retourne une instance de classeMammal
.La classe
Human
étend la classeMammal
et remplace lareadAndGet
méthode pour renvoyer l'instance deHuman
au lieu de l'instance deMammal
.Pour appeler,
readAndGet
nous devrons gérerIOException
parce que c'est une exception vérifiée et que le mammifère lereadAndMethod
lance.Et nous savons que pour le compilateur
mammal.readAndGet()
est appelé à partir de l'objet de la classe,Mammal
mais au moment de l'exécution, la JVM résoudra l'mammal.readAndGet()
appel de méthode en un appel de la classeHuman
car ellemammal
tientnew Human()
.La méthode
readAndMethod
fromMammal
est lancéeIOException
et parce que c'est un compilateur d'exceptions vérifié, nous forcera à l'attraper chaque fois que nous appelonsreadAndGet
lemammal
Supposons maintenant que
readAndGet
inHuman
lève une autre exception vérifiée, par exemple Exception et nous savons qu'ilreadAndGet
sera appelé à partir de l'instance deHuman
parce quemammal
tientnew Human()
.Parce que pour le compilateur, la méthode est appelée à partir de
Mammal
, donc le compilateur nous forcera à gérer uniquement,IOException
mais au moment de l'exécution, nous savons que la méthode lanceraException
exception qui ne sera pas gérée et notre code sera interrompu si la méthode lève l'exception.C'est pourquoi il est empêché au niveau du compilateur lui-même et nous ne sommes pas autorisés à lever une exception vérifiée nouvelle ou plus large car elle ne sera pas gérée par JVM à la fin.
Il existe également d'autres règles que nous devons suivre lors du remplacement des méthodes et vous pouvez en savoir plus sur Pourquoi nous devrions suivre les règles de remplacement de méthode pour en connaître les raisons.
la source
Quelle explication attribuons-nous à ce qui suit
La classe DerivedClass.java lève une exception lors de la compilation lorsque la méthode d'impression lève une exception, la méthode print () de la classe de base ne lève aucune exception
Je peux attribuer cela au fait qu'Exception est plus étroite que RuntimeException, cela peut être No Exception (Erreur d'exécution), RuntimeException et leurs exceptions enfants
la source
La méthode de substitution de la sous-classe ne peut lever que plusieurs exceptions vérifiées qui sont des sous-classes de l'exception vérifiée de la méthode de la superclasse, mais ne peut pas lever plusieurs exceptions vérifiées qui ne sont pas liées à l'exception vérifiée de la méthode de la superclasse
la source
Java vous donne le choix de restreindre les exceptions dans la classe parent, car il suppose que le client restreindra ce qui est intercepté . À mon humble avis, vous ne devriez essentiellement jamais utiliser cette «fonctionnalité», car vos clients peuvent avoir besoin de flexibilité sur la route.
Java est un vieux langage mal conçu. Les langues modernes n'ont pas de telles restrictions. Le moyen le plus simple de contourner cette faille est de toujours créer votre classe de base
throw Exception
. Les clients peuvent lancer des exceptions plus spécifiques mais élargir considérablement vos classes de base.la source
Règle de gestion des vérifications et des exceptions non vérifiées sur les méthodes remplacées
- Lorsque la méthode de la classe parent ne déclare aucune exception, la méthode de substitution de classe enfant peut déclarer ,
-Lorsque la méthode de la classe parent déclare une exception non vérifiée, la méthode de substitution de la classe enfant peut déclarer ,
- Lorsque la méthode de la classe parent déclare une exception vérifiée, la méthode de substitution de la classe enfant peut déclarer ,
Toutes les conclusions ci-dessus sont vraies, même si la combinaison d'exceptions cochées et non cochées est déclarée dans la méthode de la classe parent
Réf
la source