Exception et inheritance en Java

Supposons que nous ayons ce problème

public class Father{ public void method1(){...} } public class Child1 extends Father{ public void method1() throws Exception{ super.method1(); ... } } 

Child1 étend Father et remplace method1 mais étant donné l’implémentation, Child1.method1 lève maintenant une exception. Cela ne comstackra pas car la méthode de substitution ne peut pas générer de nouvelles exceptions.

Quelle est la meilleure solution?

  • Propager l’exception requirejse au Father . Pour moi, cela va à l’encontre de l’encapsulation, de l’inheritance et de la POO générale (le Father lève potentiellement une exception qui ne se produira jamais).
  • Utilisez plutôt une RuntimeException ? Cette solution ne propage pas l’ Exception au Father , mais la documentation Oracle et d’autres sources indiquent que la classe des exceptions doit être utilisée lorsque “le code client ne peut rien faire”. Ce n’est pas ce cas, cette exception sera utile pour récupérer blablabla (pourquoi est-il erroné d’utiliser RuntimeException place?).
  • Autre..

Utiliser RTE n’est pas une mauvaise idée. Ceci est la méthodologie du framework Spring et cela fonctionne assez bien. Si vous implémentez une application, utilisez probablement cette solution.

Si toutefois vous implémentez une bibliothèque qui expose l’API IMHO, vous devez utiliser une exception vérifiée. Dans ce cas, vous devez créer votre propre exception, par exemple BaseException . La méthode method() de Father lancera. ChildException extends BaseException et declare method1() de la classe enfant pour la lancer.

Cela ne rompt pas l’encapsulation: la classe de base lève une exception de base. Il n’a aucune idée de l’exception concrète. La classe enfant lève une exception concrète qui étend toutefois l’exception de base et peut donc être traitée par le code client comme une exception de base.

À titre d’exemple, je peux vous donner IOException et FileNotFoundException qui l’étend. Vous pouvez FileInputStream un stream d’entrée capturant une IOException lorsque le stream concret est FileInputStream et qu’il lève une FileNotFoundException . Mais le client ne le sait pas. Il attrape IOException .

Si la méthode super class ne déclare pas une exception, la méthode substituée par la sous-classe ne peut pas déclarer une exception vérifiée . Donc, vous ne pouvez utiliser qu’une exception non contrôlée.

Une autre option consiste à autoriser la classe Super à déclarer une ParentException , puis les méthodes substituées par un enfant peuvent déclarer toutes les exceptions qui sont des enfants de la ParentException

Dépend de ce qui lève l’exception dans Child1. Si ses conditions préalables, etc., vous pouvez toujours utiliser l’une des sous-classes de RuntimeException telle que IllegalArgumentException.

Cependant, s’il existe une sorte d’exception CheckedException, la logique vous suggère de gérer cette méthode elle-même et d’afficher le message d’une autre manière.

Je pense que la règle générale est que

si vous savez comment vous en occuper .. utilisez une exception vérifiée, exception non vérifiée

La partie “jette” fait partie de la signature de la méthode.
C’est pourquoi la méthode de la classe “enfant” n’est pas une substitution de la méthode de la classe parente.

Propager l’exception requirejse au père .. pour moi, cela va à l’encontre de l’encapsulation, de l’inheritance et de la POO générale (le père peut potentiellement lancer une exception qui ne se produira jamais)

Au contraire: c’est bon OO. Image du côté de l’appelant:

 Father f = factory.getSomeImplementation(); f.method1(); // user has no chance to see the `Exception` of Child coming... 

L’usine peut renvoyer une instance de Father ou Child ou quelque chose de complètement différent comme Brother . Mais le contrat de method1 doit être le même dans tous les cas. Et ce contrat comprend des exceptions vérifiées. C’est le principe de substitution de Liskov, l’une des règles de base de OO.

Ainsi, si l’exception fait partie du contrat commercial de method1 elle doit être déclarée à la racine. Si ce n’est pas le cas (par exemple, une vérification d’argument simple), une RuntimeException est la route à suivre de toute façon (c’est-à-dire même sans inheritance).