Tous les langages modernes possèdent
un mécanisme pour le traitement des erreurs qui peuvent se produire lors de
l'exécution. Dans JAVA, en cas de fonctionnement anormal, une exception
est déclenchée. C'est une instance de la classe Exception.
Si une méthode
peut potentiellement générer une exception, il faut obligatoirement la traiter
sans quoi il se produit une erreur lors de la compilation. Ainsi la méthode
run( ) utilisée lors des animations peut provoquer l'exception "InterruptedException".
Cette méthode doit toujours comporter les blocs try et catch qui sont utilisés
dans JAVA pour la gestion des erreurs.
Par contre, le traitement des erreurs déclenchées
par les classes de java.lang est facultatif car ces erreurs peuvent se produire
à tout moment.
Une erreur non traitée dans
un bloc de code se propage vers les blocs supérieurs.
Pour introduire les exceptions, nous allons examiner un exemple simple. Dans l'applet suivante, l'utilisateur doit taper une nombre entier N et le programme effectue ensuite la division de 1000 par le nombre N.
import
java.applet.*;
import java.awt.*;
public
class excep0 extends Applet
{ int
i=1000,resultat,n;
String
s="100";
Font font
= new Font("Helvetica",0,12);
Label
lb1,lb2;
TextField tf1=new
TextField(""+s,5);//entrée
de N
TextField
tf2=new TextField(" ",5);//affichage
résultat
public
void init()
{ setBackground(Color.lightGray);
setFont(font);
lb1=new
Label("N =",0);
add(lb1); add(tf1);//saisie
du nombre N
tf1.setForeground(Color.red);
lb2=new
Label("1000/N =",0);
add(lb2); add(tf2);
tf2.disable();}//réservé
à l'affichage
public
boolean action(Event evt, Object arg)
{ if
(evt.target==tf1) s=tf1.getText();
else
return super.action(evt,arg);
repaint(); return
true;}
public
void paint(Graphics g)
{ g.drawString("Entrer
un entier N",20,60);
n=Integer.parseInt(s);//conversion
chaîne vers entier
resultat=i/n;
tf2.setText(String.valueOf(resultat));}
}
Lors de l'exécution de ce programme, il peut se produire deux
types d'erreurs.
a) l'utilisateur entre une chaîne qui correspond à un nombre
réel ou une chaîne non convertible en nombre. Dans ces deux cas la machine virtuelle
déclenche une exception "NumberFormatException" au niveau de
l'instruction n = Integer.parseInt(s).
b) l'utilisateur
entre un zéro. La machine virtuelle déclenche alors une exception "ArithmeticException"
lors de l'exécution de resultat = i/n.
Au
niveau de l'applet apparemment rien ne se passe (tf2 reste inchangé) mais si
l'on examine la console JAVA,
on constate que la machine virtuelle émet des messages qui traduisent la détection
puis la remonté de l'erreur puisqu'elle n'est pas traitée. On peut, au passage, noter le nombre
de couches logicielles mises en oeuvre (et ce de manière transparente pour le programmeur)
par la machine virtuelle.
Pour N, taper par exemple "2.5" puis "toto" et enfin "0"
Pour capturer l'exception, il suffit d'utiliser les instructions
try (essayer) et catch (attraper). Dans le bloc try, on
place toutes les instructions qui peuvent produire une erreur. L'instruction
catch précise la nature de l'exception qui peut survenir. Cette instruction
doit toujours être suivie d'un bloc (délimité par deux accolades { et
}) même si ce bloc est vide ou contient une seule instruction. Dans le bloc,
on peut traiter ou non l'exception.
Si plusieurs exceptions peuvent se produire
dans le bloc try, on peut utiliser successivement plusieurs clauses catch.
On peut modifier l'exemple ci-dessus
en remplaçant sa méthode paint( ) par la méthode ci-dessous qui traite les deux
exceptions possibles. Dans les variables de classe de l'applet, il faut
ajouter les booléens err1 et err2. Le bloc try contient les deux instructions
pouvant provoquer une erreur.
En cas de division par 0, le bloc qui suit l'instruction
catch(ArithmeticException err) positionne le booléen err1 à false. Il est possible
de récupérer avec err un message sur la nature précise de l'erreur.
Si s ne
représente pas un entier, le bloc qui suit l'instruction catch(NumberFormatException
e) positionne le booléen err2 à false.
La suite de la méthode affiche selon
les cas un message d'erreur ou le résultat final. Il faut bien sûr repositionner
les booléens pour pouvoir continuer à utiliser le programme avec des données
valides.
Si l'on introduit dans le code la clause try et la clause catch
qui correspond à l'erreur, la machine virtuelle n'émet plus de messages même
si le bloc catch est vide.
public
void paint(Graphics g)
{ g.drawString("Entrer
un entier N",20,60);
try{ //bloc
try
n=Integer.parseInt(s);
resultat=i/n;}//fin
du bloc try
catch
(ArithmeticException e) {err1=true;}// {
et } impératifs
catch
(NumberFormatException e) {err2=true;}
if
(err1){
g.drawString("Division
par 0",20,80);
g.drawString(""+e,20,100);
err1=false;} //pour
la saisie suivante !
else
if (err2){
g.drawString("Entrer
un ENTIER !!!",20,80);
g.drawString(""+e,20,100);
err2=false;}
else
tf2.setText(String.valueOf(resultat));}
Pour N, taper par exemple "2.5" puis "toto" et enfin "0"
Examiner la console JAVA et vérifier que la machine virtuelle n'envoie plus de messages quand on tape une valeur de N non valide.
Quand on désire que certaines instructions soient exécutées même en cas d'erreur, on peut inclure à la suite des clauses catch un bloc finally. Si l'exception détectée correspond à l'un des blocs catch, les instructions de ce bloc sont exécutés et ensuite on exécute celle du bloc finally. Si aucun catch ne correspond à l'exception générée, le bloc finally est immédiatement exécuté. La méthode paint ci-dessous utilise cette technique.
public
void paint(Graphics g)
{ err1=false; err2=false;//effacement
de erreurs antérieures
g.drawString("Entrer
un entier N",20,60);
try{
n=Integer.parseInt(s);
resultat=i/n;}
catch
(ArithmeticException e) {
err1=true;
g.drawString("Division
par 0",20,80);}
catch
(NumberFormatException e) {
err2=true;
g.drawString("Entrer
un ENTIER !!!",20,80);}
finally{ //toujours
exécuté
if
(!err1 && !err2)
tf2.setText(String.valueOf(resultat));}}
La majorité des packages de JAVA peuvent générer des exceptions. JAVA effectue à la compilation et à l'exécution de multiples contrôles : c'est pourquoi on peut considérer que c'est un langage sûr.
Pour obtenir la liste complète des exceptions, il faut examiner dans la documentation JAVA la liste des classes de chaque package.
Pour le package java.lang les exceptions les plus souvent rencontrées sont ArithmeticException, NumberFormatException, IllegalArgumentException (par exemple racine carrée d'un nombre négatif), ArrayIndexOutOfBoundsException (indice de tableau incorrect), NullPointerException (tentative d'utilisation d'un objet déclaré mais non crée) et InterruptedException qui doit obligatoirement être traitée.