Générer des exceptions
Hiérarchie de classes des exceptions
Toutes les exceptions qui peuvent apparaitre dans un programme Java sont, on l'a vu à la section précédente, représentées par des classes Java. Ces classes sont organisées d'une certaine manière afin de former la hiérarchie de classes illustrée sur la figure j11.4.
Comme pour toutes les classes Java, la classe mère est bien entendu la classe Object. Juste en dessous, on retrouve la classe mère des erreurs : la classe Throwable qui représente toute entité pouvant être générée suite à une erreur. nEsuite, on peut voir deux branches : la branche Error et la branche Exception.
La branche Error
Les classes qui se trouvent dans cette branche représente des erreurs graves qu'une application ne devrait pas gérer. En effet, les erreurs que l'on retrouve dans cette branche sont des erreurs qui surviennent dans des conditions anormales, erreurs qui ne devraient pas apparaitre dans les cas normaux.
On retrouve 4 sous-classes de Error :
LinkageError: Indique qu'une classe dépend d'autres éléments qui sont indisponibles.ThreadDeath: Exception reçue par un thread qui meurt.VirtualMachineError: Indique un problème au niveau de la machine virtuelle Java : manque de ressources, ou JVM cassée.AWTError: Exception qui est générée lorsqu'une erreur grave au niveau d'AWT apparait.
La branche Exception
Dans cette branche, on retrouve des erreurs plus communes comme par exemple ArithmeticException qui représente une erreur d'arithmétique comme une division par zéro, NullPointerException qui apparait lorsqu'on travaille sur une variable de type objet qui contient la référence null, ArrayIndexOutOfBoundsException qui apparait lorsque l'on travaille avec les tableaux et qu'on tente d'accéder à un indice inexistant, ...
Les exceptions de cette branche sont donc celles que l'on va pouvoir attraper avec une instruction try-catch pour effectuer un traitement particulier. Remarquez enfin qu'on retrouve un partie séparée à cette branche : RuntimeException, on y reviendra très bientôt.
Générer une exception
Imaginons que l'on souhaite écrire une méthode qui permet de calculer la factorielle d'un nombre entier positif n. Pour rappel, la factorielle de n est notée n! et se calcule comme n = 1 . 2 . 3 . ... . n, et on a 0!=1.
Voyons tout d'abord une première manière d'écrire cette méthode. On va utiliser une précondition pour s'assurer que la méthode est bien appelée avec un entier positif.
|
|
factCette solution est assez élégante, mais si vous vous rappelez du chapitre 7, on y disait qu'on n'aime pas qu'il y aie trop de préconditions. On va donc tenter de la supprimer, mais alors, comment gérer le cas où n est négatif ?
Avec la spécification qu'on a mise là, on va se retrouver avec soit une valeur arbitraire ou alors la méthode ne se finit pas (boucle infinie), mais dans ces deux cas, il sera difficile pour celui qui utilise la méthode de savoir si tout s'est bien passé ou non.
Une première solution est d'utiliser une valeur spéciale pour le cas où n est négatif, par exemple -1.
|
|
fact avec valeur spécialeVoilà, maintenant, la personne qui utilise cette méthode va pouvoir savoir si tout s'est bien passé ou non en consultant la valeur de retour de la méthode. On peut utiliser une valeur spéciale quand on en dispose, en effet, par définition la factorielle d'un nombre est toujours positive, on peut donc utiliser tous les nombres négatifs pour signaler divers problèmes.
|
|
fact avec valeur spécialeMais comment faire lorsqu'on ne peut pas renvoyer une valeur spéciale ? Et bien, on pourrait par exemple générer une exception. Ainsi, la personne utilisant la méthode n'aurait qu'à attraper l'exception avec une instruction try-catch.
|
|
fact avec exceptionL'instruction throw
L'instruction throw permet de générer une exception. Pour l'utiliser, il faut lui fournir une référence vers un objet de type Exception. Revoyons notre exemple de factorielle, et générons une ArithmeticException si le n fourni est négatif.
|
|
fact avec exceptionVoilà, c'est aussi simple que ça de générer une exception. L'instruction throw permet de générer une exception, donc, si le flux de contrôle arrive à une instruction throw, l'exception est générée, le flux de contrôle quitte immédiatement la méthode et l'exception est propagée, remontant les appels de méthodes jusqu'à rencontrer un catch ou jusqu'à la méthode main où le programme s'arrête avec un message d'erreur comme on l'a vu à la section précédente.
Vous aurez aussi remarqué la spécification de la méthode qui a changé. En effet, lorsque qu'une méthode est susceptible de générer une exception, il faut ajouter une ligne avec @throw NomDeLexception Explication.
Exceptions sous et hors-contrôle
On retrouve deux catégories d'exceptions en Java : les exceptions sous-contrôle et les exceptions hors-contrôle. Ce qui différencie les deux types d'exceptions, c'est l'analyse de la propagation de celles-ci. La propagation des exceptions sous-contrôles est analysée pendant la compilation du programme, ce qui n'est pas le cas pour les exceptions hors-contrôle.
Qu'est-ce-que cela implique ? Et bien, si une méthode est susceptible de générer une exception sous-contrôle et que vous faites un appel vers cette méthode, pendant la phase de compilation, le compilateur va se rendre compte qu'une exception pourrait survenir, et donc, vous allez être obligé de mettre une instruction try-catch sans quoi le programme ne compilera pas.
Par contre, pour les exceptions hors-contrôle, vous ne serez pas obligé de les attraper. Toute les exceptions qui étendent la classe Exception sont des exceptions sous-contrôle, sauf toute la branche dont la classe mère est la classe RuntimeException.
Les exceptions hors-contrôle sont donc comme les erreurs de type Error, à savoir que, dans un programme normal, elles ne devraient pas être attrapée et gérée.
Comment le compilateur va-t'il savoir si une méthode est susceptible ou pas de générer une exception ? Il faut ajouter l'information dans l'entête de la méthode grâce à un nouveau mot réservé : throws (à ne pas confondre avec throw).
Les exceptions sous-contrôle offrent plus de sécurité et de garantie, en effet, l'utilisateur d'une méthode va donc devoir gérer l'exception, soit il la capture, soit il la laisse se propager. On va voir tout ça la section suivante.












Chapitre 11









