Chapitre 10
Les exceptions
10.1 Introduction : qu’est-ce qu’une exception?
De nombreux langages de programmation de haut niveau posse`dent un me´canisme permettant de ge´rer les erreurs qui peuvent intervenir lors de l’exe´cution d’un programme. Le me´canisme de gestion d’erreur le plus re´pandu est celui des exceptions. Nous avons de´ja` aborde´ le concept d’exception dans le cours sur les fonctions : lorsqu’une fonction n’est pas de´finie pour certaines valeur de ses arguments on le`ve une exception en utilisant le mot clef throw. Par exemple, la fonction factorielle n’est pas de´finie pour les nombres ne´gatifs, et pour ces cas, on le`ve une exception :
1 class F a c t o r i e l l e {
2 stat ic int f a c t o r i e l l e ( int n){
3 int res = 1;
4 if (n<0){
5 throw new PasDefini ( ) ;
6 }
7 for ( int i = 1; i <= n ; i ++) {
8 res = res ? i ;
9 }
10 return res ;
11 }
12 }
13
14 class PasDefini extends Error {}
Une exception signale une erreur comme lorsqu’un nombre ne´gatif est passe´ en argument a` la fonction factorielle. Jusqu’ici, lever une exception signifiait interrompre de´finitivement le programme avec l’affichage d’un message d’erreur de´crivant l’exception a` l’e´cran. Cependant, il est de nombreuses situations ou` le programmeur aimerait ge´rer les erreurs sans que le programme ne s’arreˆte de´finitivement. Il est alors important de pouvoir intervenir dans le cas ou` une exception a e´te´ leveé. Les langages qui utilisent les exceptions posse`dent toujours une construction syntaxique permettant de “rattraper” (ou “re´cupe´rer”) une exception, et d’exe´cuter un morceau de code spe´cifique a` ce traitement d’erreur.
Examinons maintenant comment de´finir, lever et re´cupe´rer une exception en Java.
1
Afin de de´finir une nouvelle sorte d’exception, on creé une nouvelle classe en utilisant une de´claration de la forme suivante :
class NouvelleException extends ExceptionDejaDefinie {}
On peut remarquer ici la pre´sence du mot cle´ extends, dont nous verrons la signification dans un chapitre ulte´rieur qui traitera de l’he´ritage entre classes. Dans cette construction, NouvelleException est le nom de la classe d’exception que l’on de´sire de´finir en “e´tendant” ExceptionDejaDefinie qui est une classe d’exception de´ja` de´finie. Sachant que Error est pre´de´finie en Java, la de´claration suivante de´finit la nouvelle classe d’exception PasDefini :
class PasDefini extends Error {}
Il existe de nombreuses classes d’exceptions pre´de´finies en Java, que l’on peut classer en trois cate´gories :
– Celles de´finies par extension de la classe Error : elles repre´sentent des erreurs critiques qui ne sont pas censeés eˆtre ge´reés en temps normal. Par exemple, une exception de type OutOfMemoryError est leveé lorsqu’il n’y a plus de me´moire disponible dans le syste`me. Comme elles correspondent a` des erreurs critiques elles ne sont pas normalement censeés eˆtre re´cupe´reés et nous verrons plus tard que cela permet certaines simplifications dans l’e´rciture de me´thodes pouvant lever cette exception.
– Celles de´finies par extension de la classe Exception : elles repre´sentent les erreurs qui doivent normalement eˆtre ge´reés par le programme. Par exemple, une exception de type IOException est leveé en cas d’erreur lors d’une entreé sortie.
– Celles de´finies par extension de la classe RuntimeException : elles repre´sentent des erreurs pouvant e´ventuellement eˆtre ge´reés par le programme. L’exemple typique de ce genre d’exception est NullPointerException, qui est leveé si l’on tente d’acce´der au contenu d’un tableau qui a e´te´ de´clare´ mais pas encore creé´ par un new.
Chaque nouvelle exception entre ainsi dans l’une de ces trois cate´gories. Si on suit rigoureusement ce classement (et que l’on fait fi des simplifications e´voquées plus haut), l’exception PasDefini aurait due eˆtre de´clareé par :
class PasDefini extends Exception {}
ou bien par :
class PasDefini extends RuntimeException {}
car elle ne constitue pas une erreur critique.
Lorsque l’on veut lever une exception, on utilise le mot cle´ throw suivi de l’exception a` lever, qu’il faut avoir creéé auparavant avec la construction new NomException() Ainsi lancer une exception de la classe PasDefini s’e´crit :
throw new PasDefini();
10.4. RATTRAPERUNEEXCEPTION
Lorsqu’une exception est leveé, l’exe´cution normale du programme s’arreˆte et on saute toutes les instructions jusqu’a` ce que l’exception soit rattrapeé ou jusqu’a` ce que l’on sorte du programme. Par exemple, si on conside`re le code suivant :
1 public class Arret {
2 | public stat ic void main ( String [ ] args ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 | int x = Terminal . l i r e I n t ( ) ; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | Terminal . e c r i r e S t r i n g l n ( ”Coucou1” ) ; | / / | 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 | if ( x >0){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6 | throw new Stop ( ) ; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 | } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8 | Terminal . e c r i r e S t r i n g l n ( ”Coucou2” ) ; | / / | 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9 | Terminal . e c r i r e S t r i n g l n ( ”Coucou3” ) ; | / / | 3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10 | Terminal . e c r i r e S t r i n g l n ( ”Coucou4” ) ; | / / | 4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11 | } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
12 | } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13 | class | Stop extends RuntimeException {} Coucou 1 Exception in thread "main" Stop at (:7) C’est-a`-dire que les instructions 2, 3 et 4 n’ont pas e´te´ exe´cuteés. Le programme se termine en indiquant que l’exception Stop lanceé dans la me´thode main a` la ligne 7 du fichier n’a pas e´te´ rattrapeé. 10.4 Rattraper une exception10.4.1 La construction try catchLe rattrapage d’une exception en Java se fait en utilisant la construction : Listing 10.3 – (pas de lien)1 try { 2 . . . / / 1 3 } catch ( UneException e ) { 4 . . . / / 2 5 } 6 . . / / 3 Le code 1 est normalement exe´cute´. Si une exception est leveé lors de cette exe´cution, les instructions restantes dans le code 1 sont abandonneés. Si la classe de l’exception leveé dans le bloc 1 est UneException alors le code 2 est exe´cute´ (car l’exception est re´cupe´reé). Dans le code 2, on peut faire re´fe´rence a` l’exception en utilisant le nom donne´ a` celle-ci lorsque l’on nomme sa classe. Ici le nom est e. Dans le cas ou` la classe de l’exception n’est pas UneException, le code 2 et le code 3 sont saute´s. Ainsi, le programme suivant : Listing 10.4 – (lien vers le code brut)1 public class Arret2 { 2 public stat ic void P ( ) { 3 int x = Terminal . l i r e I n t ( ) ; 4 5 if ( x >0){ 6 throw new Stop ( ) ; 7 } 8 }
produit l’affichage suivant lorsqu’il est exe´cute´ et que l’on saisit une valeur positive : Coucou 1 Coucou 3 Coucou 4 On remarquera que l’instruction 2 n’est pas exe´cute´ (du fait de la leveé de l’exception dans P. Si on exe´cute ce meˆme programme mais en saisissant une valeur ne´gative on obtient : Coucou 1 Coucou 2 Coucou 4 car l’exception n’est pas leveé. En revanche le programme suivant, dans lequel on le`ve une exception Stop2, qui n’est pas re´cupe´reé. Listing 10.5 – (lien vers le code brut)1 public class Arret3 { 2 public stat ic void P ( ) { 3 int x = Terminal . l i r e I n t ( ) ; 4 5 if ( x >0){ 6 throw new Stop2 ( ) ; 7 } 8 } 9 public stat ic void main ( String [ ] args ) { 10 Terminal . e c r i r e S t r i n g l n ( ”Coucou1” ) ; / / 1 11 try { 10.4. RATTRAPERUNEEXCEPTION
produit l’affichage suivant lorsqu’il est exe´cute´ et que l’on saisit une valeur positive : Coucou 1 Exception in thread "main" Stop2 at Arret3.P(:7) at (:15) 10.4.2 Rattraper plusieurs exceptionsIl est possible de rattraper plusieurs types d’exceptions en enchaˆ?nant les constructions catch : Listing 10.6 – (lien vers le code brut)1 public class Arret3 { 2 public stat ic void P ( ) { 3 int x = Terminal . l i r e I n t ( ) ; 4 5 if ( x >0){ 6 throw new Stop2 ( ) ; 7 } 8 } 9 public stat ic void main ( String [ ] args ) { 10 Terminal . e c r i r e S t r i n g l n ( ”Coucou1” ) ; / / 1 11 try { 12 P ( ) ; 13 Terminal . e c r i r e S t r i n g l n ( ”Coucou 2” ) ; / / 2 14 } catch ( Stop e ){ 16 } 17 } catch ( Stop2 e ){ 18 Terminal . e c r i r e S t r i n g l n ( ”Coucou 3 bis ” ) ; / / 3 bis 19 } 20 Terminal . e c r i r e S t r i n g l n ( ”Coucou4” ) ; / / 4 21 } 22 } 23 class Stop extends RuntimeException {} 24 class Stop2 extends RuntimeException {} A l’exe´cution, on obtient (en saisissant une valeur positive) : Coucou 1 Coucou 3 bis Coucou 4 10.5 Exceptions et methodes´10.5.1 Exception non rattrapee dans le corps d’une m´ ethode´Comme on l’a vu dans les exemples pre´ce´dents, lorsqu’une exception est leveé lors de l’exe´cution d’une me´thode et qu’elle n’est pas rattrapeé dans cette méthode, elle “continue son trajet” a` partir de l’appel de la me´thode. Meˆme si la me´thode est senseé renvoyer une valeur, elle ne le fait pas : Listing 10.7 – (lien vers le code brut)1 public class Arret { 2 stat ic int lance ( int x ) { 3 if ( x < 0) { 4 throw new Stop ( ) ; 5 } 6 return x ; 7 } 8 public stat ic void main ( String [ ] args ) { 10 try { 11 Terminal . e c r i r e S t r i n g l n ( ”Coucou 1” ) ; 12 y = lance ( ?2); 13 Terminal . e c r i r e S t r i n g l n ( ”Coucou 2” ) ; 14 } catch ( Stop e ) { 15 Terminal . e c r i r e S t r i n g l n ( ”Coucou 3” ) ; 16 } 17 Terminal . e c r i r e S t r i n g l n ( ”y vaut ”+y ) ; 18 } 19 } 20 class Stop extends RuntimeException {} A l’exe´cution on obtient : Coucou 1 Coucou 3 y vaut 0 10.5.2 Declaration´ throwsLorsqu’une me´thode le`ve une exception de´finie par extension de la classe Exception il est ne´cessaire de pre´ciser au niveau de la de´claration de la me´thode qu’elle peut potentiellement lever une exception de cette classe. Cette de´claration prend la forme throws Exception1, Exception2, et se place entre les arguments de la me´thode et l’accolade ouvrant marquant le de´but du corps de la me´thode. On notera que cette de´claration n’est pas obligatoire pour les exceptions de la cate´gorie Error ni pour celles de la cate´gorie RuntimeException. 10.6 Exemple resum´ e´On reprend l’exemple de la fonction factorielle : Listing 10.8 – (lien vers le code brut)10.6. EXEMPLERESUM´ E´ 1 class F a c t o r i e l l e { 2 stat ic int f a c t o r i e l l e ( int n ) throws PasDefini { / / (1) 4 if (n<0){ 5 throw new PasDefini ( ) ; / / (2) 6 } 7 for ( int i = 1; i <= n ; i ++) { 8 res = res ? i ; 9 } 10 return res ; 11 } 12 public stat ic void main ( String [] args ) { 13 int x ; 14 Terminal . e c r i r e S t r i n g ( ” Entrez un nombre ( p e t i t ) : ” ) ; 15 x = Terminal . l i r e I n t ( ) ; 16 try { / / (3) 17 Terminal . e c r i r e I n t l n ( f a c t o r i e l l e ( x ) ) ; 18 } catch ( PasDefini e ) { / / (3 bis ) 19 Terminal . e c r i r e S t r i n g l n ( ”La f a c t o r i e l l e de ” 20 +x+” n ’ es t pas d ef in i e ! ” ) ; 21 } 22 } 24 class PasDefini extends Exception {} / / (4) Dans ce programme, on de´finit une nouvelle classe d’exception PasDefini au point (4). Cette exception est leveé par l’instruction throw au point (2) lorsque l’argument de la me´thode est ne´gatif. Dans ce cas l’exception n’est pas rattrapeé dans le corps et comme elle n’est ni dans la cate´gorie Error ni dans la cate´gorie RuntimeException, on la de´clare comme pouvant eˆtre leveé par factorielle, en utilisant la de´claration throws au point (1). Si l’exception PasDefini est leveé lors de l’appel a` factorielle, elle est rattrapeé au niveau de la construction try catch des points (3) (3 bis) et un message indiquant que la factorielle du nombre entre´ n’est pas de´finie est alors affiche´. Voici deux exe´cutions du programme avec des valeurs diffe´rentes pour x (l’exception est leveé puis rattrapeé lors de la deuxie`me exe´cution) : > java Factorielle Entrez un nombre (petit):4 24 > java Factorielle Entrez un nombre (petit):-3 La factorielle de -3 n’est pas définie ! Annexe : quelques exceptions pred´ efinies´Voici quelques exceptions pre´de´finies dans Java : – NullPointerException : utilisation de length ou acce`s a` un case d’un tableau valant null (c’est a` dire non encore creé´ par un new). – ArrayIndexOutOfBoundsException : acce`s a` une case inexistante dans un tableau. – ArrayIndexOutOfBoundsException: acce`s au ieme caracte`re d’un chaˆ?ne de caracte`res de taille infe´rieure a` i. – ArrayIndexOutOfBoundsException : cre´ation d’un tableau de taille ne´gative. – NumberFormatException : erreur lors de la conversion d’un chaˆ?ne de caracte`res en nombre. |