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.