Vous êtes sur la page 1sur 45

Exceptions

Introduction

151
Solutions classiques

152
Solutions classiques

153
Solutions classiques
— INCONVENIENTS:
•Nécessite un contrôle à chaque appel
•Solution avec des tests sur les éventuels retours (switch),
compliquée, difficile à maintenir.
•Dans le code : mélange des traitements du fonctionnement normal
et ceux gérant les exceptions.
•L’erreur n’est pas forcément à corriger dans la méthode appelante
directe.
•Les constructeurs et destructeurs n’ont pas de type retour.

154
Gestion des exceptions

155
Mécanisme général d’exception en java
— Exemples d’exception
— Diviser par 0
— Accéder un tableau avec un index invalide
—…
Méthode qui appelle:

appel
Appel Méthode appelée:

Suite Retour normal
normale
Normal
Traiter
l’exception Exception
… Message d’exception
156
Mécanisme général
— Deux mécanismes en parallèle
— Traitement normal
— Traitement d’exception (exception handler)
— Quand il y a une exception
— Le traitement normal s’arrête
— Le traitement d’exception prend le contrôle

157
Traitement d’exception en chaîne

— méthode_1 appelle méthode_2, qui appelle méthode 3


Méthode_1 Méthode_2 Méthode_3

— Si méthode 3 génère une exception


— Message d’exception est envoyé à méthode_2
— Méthode_2 peut
— Traiter (attraper) l’exception
— Relancer l’exception: le message d’exception sera envoyé à
méthode_1
— Si une exception n’est traitée par aucune méthode qui appelle:
sortie du programme avec un message d’exception

158
Exemple de transmission d’exception

159
Générer une exception
— Certaines exceptions standard sont reconnues
— ArithmeticException: diviser par 0
— ClassCastException: Casting d’un objet à une
mauvaise classe
— EOFException: Lire après la fin d’un fichier
— IllegalArgumentException: paramètres illégaux
ou inappropriés
—…
— Quand une de ces exceptions est rencontrée, le
système lance (throw) un message d’exception
160
Vue générale sur les exceptions
float division (float a, float b) {
return a/b ;
}

La méthode division ne semble pas poser de problèmes. On peut cependant


remarquer qu’il peut y avoir un problème si b = 0. C’est d’autant plus gênant
que cela n’embête pas Java, qui va rendre une valeur. Autrement dit, on va
continuer le calcul avec une valeur qui n’a aucun sens, et sans le savoir. Dans le
cas précédent, il n’y avait pas d’autre possibilité que de s’arrêter. Dans ce cas-ci,
il est possible de continuer, mais ce n’est pas souhaitable. Il faut signaler qu’il y
a eu un problème à cet endroit.
Il est donc préférable, là encore, d’utiliser une Exception.

Une Exception est un problème qu’il n’est pas possible de traiter immédiatement.
161
Vue générale sur les exceptions

• Une bonne gestion des exceptions en Java permet :


- de dissocier la détection d’une anomalie de son traitement,
- de séparer la gestion des anomalies du reste du code, donc de
contribuer à la lisibilité des programmes.
• Une exception est déclenchée par une instruction throw
comportant une expression qui est un objet de type classe . Il y
a alors branchement à un ensemble d’instructions nommé
« gestionnaire d’exception ».
• Le choix du bon gestionnaire est fait en fonction de l’objet
mentionné à throw (de façon comparable au choix d’une
fonction surdéfinie).

162
L’instruction throw

public class Except01 {


/*methode qui declenche une exception*/

public static float division( float a, float b) throws DivisionParZero


{ if (b = = 0) throw new DivisionParZero("denominateur nul");
else return a/b;
}

public static void main(String[] args) throws DivisionParZero {


System.out.println (division(1,0));

System.out.println ("Merci !" ); Ceci car on appelle la méthode


} division qui est susceptible de
} générer une exception.
class DivisionParZero extends Exception
{DivisionParZero (String mes)
{ super(mes); }
163
}
• Au niveau de la méthode division, la clause throws
DivisionParZero précise que la méthode est susceptible de
déclencher une exception de type DivisionParZero .
• Il faut bien noter que la méthode ne fait que déclencher; elle
ne traite pas l’exception.
• Autre remarque très importante: la clause throws d’une
méthode doit mentionner au moins la réunion de toutes les
exceptions mentionnées dans les clauses throws des méthodes
appelées. C’est pourquoi la méthode main (appelant la
méthode division) mentionne dans sa clause throws
l’exception DivisionParZero .

164
Une bonne gestion des exceptions doit toujours permettre à l’utilisateur,
s’il le désire de pouvoir continuer l’exécution du programme après
détection d’une anomalie. Dans l’exemple précédent de la classe Except01
, la méthode division déclenche bien une exception qu’elle ne traite pas et
la méthode appelante (ie la méthode main aussi ne la traite pas non plus.
C’est pourquoi le programme ne se poursuit pas pour exécuter
l’instruction System.out.println ("Merci !" ).
L’intérêt de l’exemple précédent est simplement d’avoir des informations
plus parlantes sur la nature de l’exception.
En java, si une méthode déclenche une exception qu’elle ne traite pas,
la ou les méthodes appelantes doivent la traiter (avec un gestionnaire
d’exception.
Traitement des exceptions avec un GESTIONNAIRE D’ EXCEPTION qui
donne des informations précises sur la cause, la localisation d’une erreur…

165
Gestionnaire d’exception:
bloc try…..catch
Voyons maintenant comment procéder pour gérer convenablement les
éventuelles exceptions de type DivisionParZero que son emploi peut
déclencher. Pour ce faire , il faut :
-inclure dans un bloc dit « bloc try » les instructions dans lesquelles on
risque de déclencher une telle instruction; ce bloc se présente ainsi :
try {
// instructions
}
- faire suivre ce bloc de la définition des différents gestionnaires d’exception :
catch (DivisionParZero e)
{ //instructions
}
166
Gestionnaire d’exception:
bloc try…..catch
• L’appel aux méthodes pouvant « lancer » une erreur/exception
doit être englobé dans un bloc try…catch
– La méthode printStackTrace de l’objet Exception permet de
retracer la pile des appels de méthode, jusqu’à l’appel ayant
générée l’erreur.

try{
// Ecrire dans un fichier
}catch(FileNotFoundException e){
e.printStackTrace();
}

167
Exemple avec gestionnaire d’exception

public class Except02 {


/*methode qui declenche une exception*/

public static float division( float a, float b) throws DivisionParZero


{ if (b = = 0) throw new DivisionParZero ( );
else return a/b; }
/* là on traite vraiment l’exception*/
public static void main(String[] args)
try { System.out.println (division(1,0)); Ici le gestionnaire d’exception
System.out.println ("Merci !" ); ne fait rien du tout (ie aucune
} information n’est transmise au
gestionnaire).
catch (DivisionParZero e )
{ System.out.println(" le denominateur ne peut pas etre nul");
}
}}
class DivisionParZero extends Exception
{ }{ }
168
Lancement d'exception
• L'exécution de certaines méthodes peut provoquer
une erreur que l'application devra prendre en
compte.
– On signale que la méthode peut lancer une
exception en ajoutant un throws à la signature de
la méthode.
public EmployeVO getEmploye(String login, String password) throws ErreurDomaine { ...}

169
Clôture des traitements avec finally
• Dès qu’une exception intervient, les traitements suivants dans le
bloc try sont évités.
– Il peut néanmoins être nécessaire d’effectuer d’autres traitements
• libérer les ressources, comme la fermeture de la connexion vers un fichier

• On utilise pour cela le bloc finally, qui sera toujours exécuté


(avec
try{ ou sans passage dans le bloc catch)
//Ecrire dans un fichier
}catch(Exception e){
e.printStackTrace();
}finally{
// Libération de la ressource (fermeture d'une connexion avec close())
}

Si l'exception n'est pas relancée mais traitée dans le bloc catch, l'exécution de la
méthode se poursuit après le dernier catch
170
finally

— Exécuter un bloc quel que soit l’exception


try
{
statement
...
}
finally
{
statement Exécuter finally même si le
... bloc try lance une exception
}

171
finally
— Souvent combiné avec catch
try
{
statement
...
}
catch (ExceptionClass exceptionObject)
{
statement
...
} Même si une exception est
finally attrapée, finally sera
{ toujours exécuté
statement
... Utile pour s’assurer de
}
certaine sécurité (cleanup)

172
Là aussi à l’exécution, l’exception causée par la division par zéro est lancée
dans la méthode division et traitée par le bloc catch (DivisionParZero e )
dans la méthode appelante. Mais, comme précédemment l’instruction :
System.out.println( « Merci ! ») ne sera pas exécutée. Ceci parce que tout
simplement dès qu’on sort du bloc try pour entrer dans le bloc catch, on
ne peut plus revenir dans le try.
Si on veut continuer l’exécution des instructions après l’exception, il faut
utiliser l’instruction finally après catch.
Cette dernière veut dire : qu’il y ait exception ou pas les instructions se
trouvant dans ce bloc seront exécutées. On écrit:
finally {
System.out.println( « Merci ! »)
}

173
Exceptions prédéfinies
— En Java, il existe deux classes intéressantes dérivées de la classe
Throwable :
— la classe Error, d'où proviennent les erreurs système souvent
irrécupérables
— représentées par les classes suivantes :
— VirtualMachineError : indique de graves problèmes sur la machine
virtuelle Java,
— AWTError : indique une sérieuse erreur du système de gestion de
l'interface
— utilisateur AWT (Abstract Window Toolkit),
— ThreadDeath : indique l'arrêt inopportun d'un Thread,
— LinkageError : indique des problèmes de liaisons entre des classes.

174
Exceptions prédéfinies
— Les exceptions provenant de la classe Error dépassent souvent le
domaine de compétence d'un programmeur. Toutefois, certaines
peuvent être gérées, à l'image d'une erreur du type OutOfMemoryError
(plus de mémoire).
— la classe Exception, d'où sont issues les fameuses exceptions
déclenchées par le compilateur.
— Les exceptions sont donc de véritables objets créés suite à la détection
d’une anomalie dans le déroulement du programme.
— Contrairement à celles de la classe Error, les exceptions de la classe
Exception peuvent et dans la plupart des cas, doivent être interceptées.

175
Architecture API Exception

176
Exceptions : classes particulières

❚ Les exceptions sont classées en 3 classes


❚ Error : exceptions pour les erreurs systèmes comme pas assez de
mémoire. En général, on ne peut rien faire, sinon quitter
❚ RuntimeException : erreur classique, mais le compilateur n’oblige
pas l’utilisateur à déclarer que ses méthodes peuvent déclencher une
exception. Pratique, mais des vérifications en moins. Toutes les
exceptions arithmétiques, erreurs d’indice de java sont de ce type par
exemple.
❚ Exception : erreur classique, mais le compilateur oblige l’utilisateur à
déclarer que sa méthode peut déclencher cette exception par le mot
clé throws. Les exceptions générées par les Entrées sorties par
exemple.

177
Classe Throwable

— 4 constructeurs
— Thrwoable getCause()
— Cause de cette exception (ou null)
— String getMessage():
— message envoyé par l’exception
— String toString()
— Générer un message décrivant l’exception
— …

178
Classe Exception
— Constructeurs
Exception()
Constructs a new exception with null as its detail message.

Exception(String message)
Constructs a new exception with the specified detail message.

Exception(String message, Throwable cause)


Constructs a new exception with the specified detail message and cause.

Exception(Throwable cause)
Constructs a new exception with the specified cause and a detail message of
(cause==null ? null : cause.toString()) (which typically contains the class and
detail message of cause).

179
Présentation de Throwable

Constructeurs Rôle
Throwable()

Throwable(String) La chaîne en paramètre permet d'ajouter un


message de description de l'exception.

Méthodes Rôle
String getMessage( ) lecture du message

void printStackTrace( ) affiche l'exception et l'état de la pile d'exécution au


moment de son appel

180
Description de l’exception
Runtime dérivées du package java.lang

ArithmeticException Exception sur une opération arithmétique, (ex: division d'un entier par zéro )
ArrayStoreException Tentative de stocker dans un tableau un élément qui n'est pas du type des éléments du
tableau ou castable dans ce type
ClassCastException Tentative de cast d'un objet dans un type incorrecte
IllegalArgumentException Méthode appelée avec un mauvais argument ou invoquée sur un mauvais objet
IllegalThreadStateException Un thread était dans un état inadéquat pour l'opération requise
NumberFormatException Conversion dans un type numérique une chaîne de caractères mal formatée
IllegalMonitorStateException Le thread courant a tenté d'attendre ou de prévenir d'autres threads, sur un objet non
verrouillé par ce thread. Cette exception est déclenchée par les méthodes wait () et notify ()
de la classe Object
IndexOutOfBoundsException Un indice (sur un tableau, une chaîne) ou un intervalle défini par deux indices ont dépassé les
limites inférieures ou supérieure
ArrayIndexOutOfBoundsException pour les tableaux (indice négatif ou supérieur ou égal à la taille du tableau)
StringIndexOutOfBoundsException pour les chaînes de caractères
NegativeArraySizeException Tentative de créer un tableau ou une chaîne avec une taille négative
NullPointerException Tentative d'utiliser une référence null alors qu'une référence sur un objet valide était
attendue
SecurityException Violation de sécurité
181
Description des erreurs

LinkageError Super classe des classes d'erreurs déclenchées quand le lien vers une classe est
impossible (classe ou méthode inexistante, fichier .class corrompu,...). Ces erreurs
surviennent la plupart du temps quand la Machine Virtuelle Java continue à utiliser
un ancien fichier .class d'une classe qui a changé. Dans ce cas, vérifier les trois
points suivants et recompiler la classe si nécessaire :
1. Dates du fichier .class et du fichier source .java.
2. Répertoire de provenance du fichier .class en consultant le CLASSPATH utilisé.
3. Unicité du fichier .class : modification de l'arborescence de développement en
laissant d'anciens fichiers .class utilisés par inadvertance ?
ClassCircularityError Référence circulaire détectée dans la hiérarchie d'une classe
ClassFormatError Une classe n'est pas au bon format. Cette erreur peut être déclenchée par la méthode
defineClass () de la classe ClassLoader.
IncompatibleClassChangeError Super classe des classes d'erreurs déclenchées quand la Machine Virtuelle Java utilise un
champ ou une méthode qui a été changé ou supprimé. Comme le compilateur interdit ces
erreurs, elles ne peuvent survenir que si la Machine Virtuelle utilise des fichiers .class qui ne sont
pas à jour (voir aussi la super classe LinkageError).

AbstractMethodError Tentative d'appeler une méthode abstract.


IllegalAccessError Tentative d'accéder à un champ ou méthode inaccessible (elle est devenue private par exemple).

InstantiationError Tentative d'instancier une classe abstract ou une interface


NoSuchFieldError
182 Tentative d'accéder un champ qui n'existe pas
Description des erreurs

NoSuchMethodError Tentative d'accéder une méthode qui n'existe pas


NoClassDefFoundError La classe requise n'a pas été trouvée par la Machine Virtuelle Java. Cette erreur survient le plus
souvent parce que la classe n'a pas été retrouvée avec le CLASSPATH utilisé.

UnsatisfiedLinkError Une méthode native n'a pas été trouvée par la Machine Virtuelle Java.
VerifyError La classe est incohérente.
ThreadDeath Cette erreur est déclenchée par la méthode stop () sans paramètre de la classe Thread.

VirtualMachineError Super classe des classes d'erreurs déclenchées quand la JVM n'est plus en mesure de
fonctionner.
InternalError Etat incohérent de la Machine Virtuelle.
OutOfMemoryError La JVM n'a pas assez de mémoire pour instancier un nouvel objet même après que le Garbage
Collector soit intervenu.
StackOverflowError Un débordement de pile est survenu, par exemple suite à un appel récursif dans une méthode
sans condition d'arrêt.
AWTError Une erreur est survenue pendant l'utilisation d'AWT. Cette erreur est utilisée en cas d'erreur
d'initialisation du toolkit AWT (pas de DISPLAY sous X11 par exemple) ou de l'impression.

183
Traitement d'exceptions prédéfinies

public class Except03 {


public static int [] suite( int n) throws NegativeArraySizeException {
int tab[ ] = new int [n];
if (n < 0 ) throw new NegativeArraySizeException ( );
for( int i = 0;i < tab.length;i++) tab[i] = i;
return tab; }
public static float division( float a, float b) throws ArithmeticException
{ if (b =§%m;
} Pile d’exécution
public static void main(String[] args) { du programme
try { System.out.println(suite(-5)); System.out.println(division(1,2)); }
catch (NegativeArraySizeException ex){ System.out.println("erreur: taille du
tableau négative »; ex.printStackTrace(); }
catch(ArithmeticException e)
{System.out.println("message d'erreur: division par zéro";
} }}

184
Exemple avec plusieurs gestionnaires d’exception

public class Except03 {


public static int [] suite( int n) throws NegativeArraySizeException
{
int tab[ ] = new int [n];
if (n < 0 ) throw new NegativeArraySizeException( );
for( int i = 0;i < tab.length;i++) tab[i] = i;
return tab; }
public static float division( float a, float b) throws DivisionParZero
{ if (b = = 0 ) throw new DivisionParZero( );
return a / b;
}
public static void main(String[] args) {
try { System.out.println(suite(-5)); System.out.println(division(1,2)); }
catch (NegativeArraySizeException ex)
{ System.out.println("erreur: "+ex.getMessage()); }
catch(DivisionParZero e)
{System.out.println("message d'erreur: "+e.getMessage());
} }}
185 class DivisionParZero extends Exception{ }
Dans cet exemple, le choix du bon gestionnaire est toujours réalisé en examinant le type
de l’objet transmis au bloc catch (se rappeler que lancer une exception c’est produire un
objet de type classe d’exception.
Si, en parcourant un bloc try une exception est rencontrée mais n’est traitée par aucun
bloc catch, alors c’est la classe standard de l’exception ( faisant partie de l’API) qui est
invoquée par le compilateur pour la traiter.
En réalité, lorsque vous créez des classes d’exception, vous ne faites que personnaliser une
classe d’exception de l’API dans le but d’avoir des informations plus parlantes quant à la
nature de l’exception.
Aussi, on n’est pas sensé, à priori, connaître les classes de bases de l’API pour la
gestion des exceptions (exemple savoir qu’il y a une classe ArithmeticException qui
gère les erreurs dues à des calculs algébriques impossibles ou erronées). Mais, il faut savoir
qu’il y a une super classe Exception qui englobe la gestion de toutes formes d’exception
(et il est toujours possible de dériver de cette classe pour gérer une exception
quelconque).

186
Définir ses propres exceptions

— Les classes d’exception prédéfinies ne sont pas suffisamment explicites


— On a besoin de faire la différence entre les exceptions pour leurs
traitements
— Définir une sous-classe d’exception

public class NoDataException extends Exception {


public NoDataException () {
super();
}
public NoDataException (String s) { constructeurs
super(s);
}
}
— Définir une hiérarchies de classes d’exception

187
Exemple
class TemperatureException extends Exception {
}

class TooColdException extends TemperatureException {


}

class TooHotException extends TemperatureException {


}

188
Penser Exception comme des
classes / sous-classes
Une TooColdException
est aussi une
TempretureException,
Exception, Throwable

Attention aux catches:


Catch une sous-classe
avant une super-classe

189
Checked vs. Unchecked
— Checked exception
— Vérifiée par le compilateur
— Si le programme peut générer une telle exception, il doit
— Soit la traiter dans le programme
— Soit la retransmettre à l’appelant (avec throws dans l’entête)
— Typiquement générée à cause de l’environnement
— Exemple, IOException
— public void getSomeData () throws FileNotFoundException, SecurityException
— Unchecked exception
— RuntimeException
— Problème du programmeur (mauvaise utilisation d’une méthode, d’un objet, …)
— Le compilateur ne la vérifie pas
— Si un programme peut générer une telle exception, le programme n’a pas à la
signaler dans l’entête
— public int division(înt a, int b) {return a/b; }

190
Checked vs. Unchecked exception

191
Lancer une checked exception

— Signaler au compilateur qu’une méthode peut lancer une


exception (non attrapée, non traitée)
public void methode() throws ExceptionClass
— Exemple
public void skip () throws IOException {
String s;
s = input.readLine();
}
— Si une exception apparaît, transmise à l’appelant (caller)

192
Traitement des "unchecked exceptions"

• Les catégories RuntimeException, Error et leurs classes dérivées


n'ont pas besoin d'être traitées dans des blocs try...catch, même
si une méthode relance explicitement une exception de ce type.

– C'est la JVM qui se charge du traitement, et de l'affichage de l'état


de la pile sur la console.

– Sans cette gestion automatisée, le code de traitement des erreurs


serait plus important que le code utile.

193
Conclusion

194