TUTORIELS 
Introduction aux "exceptions" en Java
Les exceptions constituent une solution élégante pour dissocier le code lié au fonctionnement normal du programme et celui lié à la gestion des erreurs.  (5 janvier 2002)
 

Si le langage que vous utilisez le permet, orientez votre politique de gestion des erreurs de votre programme autour des exceptions. Celles-ci permettent en effet de dissocier clairement le code lié au déroulement normal de votre application et celui dédié à la gestion des erreurs. Cela influera positivement sur la lisibilité de vos sources.

Nous avions précedemment étudié les exceptions avec le langage Javascript, mais sachez également qu'elles sont aussi disponibles avec le C++, le récent C#, ou dans un autre registre, Cold Fusion, alors que Php les adoptera bientôt.

Les origines des exceptions

Une exception se produit, comme son nom l'indique, lorsqu'une situation exceptionnelle survient pendant l'exécution de l'un de vos programmes Java. Elles se situent donc en aval de la phase de compilation. Nous allons voir cependant que le compilateur joue un rôle important pour certaines classes susceptibles de lancer un type particulier d'exceptions.

"Situation exceptionnelle", c'est vite dit. Il n'est pourtant pas si "difficile" pour un programmeur de générer une exception : accéder à l'indice d'un tableau non défini ou une division par zéro (liste hélas non exhaustive) suffisent à produire respectivement les exceptions suivantes : "IndexOutOfBoundsException" et "ArithmeticException".

Si les programmeurs sont parfois désespérés à la vue du nombre "d'alertes" ou autres "warning" plus ou moins sévères générés par leur compilateur, ces derniers permettent d'augmenter la fiabilité future de l'application lorsqu'elle s'exécutera. Comprendre par là que plus un compilateur est sévère au départ, plus le risque de rencontrer des problèmes à l'exécution ensuite est réduit. Les exceptions sont alors un bon moyen de détecter des problèmes éventuels.

Une exception est en fait un objet crée lorsqu'une situation anormale se produit pendant l'exécution de votre programme. Les exceptions sont toujours issues de la classe Throwable.
Deux sous-classes sont alors notables, elles sont dérivées de la classe Throwable et se nomment "Error" et "Exception".

Bien qu'il soit possible d'intercepter les classes d'exceptions de la classe Error (ThreadDeath, LinkageError et VirtualMachineError) notre pouvoir à leur égard est limité et concerne des conditions que nous ne sommes pas censés gérer, en tout cas pas couramment (arrêt d'un thread en cours d'exécution, création d'un objet pour un type de classe inexistant, grave problème sur la machine virtuelle Java...).

En conséquence, nous allons davantage nous focaliser sur les exceptions représentées par des sous-classes de la classe "Exception" (paquetage java.lang). Non seulement il est possible d'intercepter ces exceptions mais il est également obligatoire de le faire pour certaines d'entre elles.

En effet, on peut diviser en deux catégories les exceptions représentées par les classes dérivées de la classe "Exception" : les exceptions dont la classe de base est "RuntimeException" (dérivée de "Exception"), et les autres. Il n'est pas obligatoire de gérer les exceptions qui pourraient se produire avec les premières, par contre le compilateur refusera systématiquement de... compiler si une méthode capable de provoquer une exception représentée par une sous-classe de la classe "Exception" n'est pas gérée (par un bloc de type try / catch comme nous le verrons) ou tout du moins signalée comme susceptible de générer ce type d'exceptions.

Analysons de plus près ce dernier point à l'aide de deux exemples :

(ZeroDivide.java)
public class ZeroDivide
{
     static public void main(String[] args)
     {
          int a = 3;
          int b = 0;

          System.out.println("Resultat de la division : " + a/b);
     }
}


Ce bout de code se compile sans problème, par contre c'est au niveau de l'exécution qu'une exception apparaît :

Exception in thread "main" java.lang.ArithmeticException: / by zero at ZeroDivide.main(ZeroDivide.java:8)

"java.lang.ArithmeticException" représente le nom de la classe de l'objet reçu.
Nous verrons plus tard comment capturer cette exception et éviter ainsi d'attirer l'attention des utilisateurs de votre programme sur la ligne 8 de votre code source...

Si le premier exemple s'est compilé sans problème c'est que la sous-classe ArithmeticException dérive de "RuntimeException".

Voyons ce qu'il se passe quand ça n'est pas le cas :

(TaperTouche.java)
public class TaperTouche
{
     static public void main(String[] args)
     {
          System.out.println("Tapez une touche pour terminer le programme");
          System.in.read();
     }
}

La compilation est impossible...

TaperTouche.java:6: unreported exception java.io.IOException; must be caught or
declared to be thrown

... En effet la méthode "read()" de l'objet "in" est susceptible de lever une exception "d'entrée / sortie" (IOException).

Passons maintenant à la correction de ces deux exemples.

Les blocs "try" / "catch"

Découvrons brièvement ce qu'il faut retenir d'essentiel à propos de la construction "try... catch... finally" (nous reviendrons plus en détail sur celle-ci dans un tutoriel ultérieur sur le même sujet).

Reprenons notre premier exemple. Il compilait mais générait (levait) une exception que nous souhaiterions désormais faire disparaître (capturer). Voici donc le même code source doté des corrections adéquates :

(ZeroDivide.java)
public class ZeroDivide
{
     static public void main(String[] args)
     {
          int a = 3;
          int b = 0;

          try
          {

               System.out.println("Resultat de la division : " + a/b);
               System.out.println("Instructions suivant la division...");
          }
          catch(ArithmeticException e)
          {
               System.out.println("Une exception s'est produite ! (ArithmeticException)");
          }


          System.out.println("Instructions qui suivent le bloc catch...");
     }
}

Le bloc "try" cerne le bout de code susceptible de générer l'exception que nous cherchons à capturer. Le bloc "catch" doit suivre immédiatement le bloc "try". Celui-ci est facultatif, il peut en effet laisser sa place à un bloc "finally" (que nous détaillerons dans un autre tutoriel) qui lui permet d'exécuter systématiquement, qu'une exception se produise ou non, le code qu'il contient (libération de ressources, fermeture de fichier par exemple).
Le bloc catch permet de définir une action suite à un type précis d'exception. Un catch se définit par le type d'exception qu'il peut capturer. Plusieurs "catch" peuvent se suivre, chacun pouvant capturer un type d'exception défini par le programmeur.

Si vous exécutez cette version corrigée de l'exemple "ZeroDivide", l'exception n'a pas disparue mais elle a été "capturée" et provoque l'affichage de notre message définit dans le catch correspondant.

De plus, il a été rajouté ici deux affichages, destinés à mieux cerner le comportement du programme lors de la levée de l'exception. Lorsqu'on exécute cette version modifiée de "ZeroDivide.java" on obtient à l'écran :

Une exception s'est produite ! (ArithmeticException)
Instructions qui suivent le bloc catch...

Lorsque l'exception est levée le bloc try est interrompu, le programme exécute les instructions situées dans le bloc catch correspondant, puis passe à l'instruction suivant le bloc catch.

Voyons maintenant les modifications à apporter au second exemple :

(TaperTouche.java)
import java.io.IOException;

public class TaperTouche
{
     static public void main(String[] args)
     {
          System.out.println("Tapez une touche pour terminer le programme");
          try
          {

               System.in.read();
          }
          catch(IOException e)
          {
               System.out.println("Une IOException a été détectée !");
          }

     }
}

Même principe que précedemment, avec en plus l'import de la classe "java.io.IOException" dont est issue l'exception susceptible de se produire.

Ce tutoriel n'est pas exhaustif sur la gestion des erreurs en Java. Nous aborderons donc dans un prochain article d'autres techniques relatives aux exceptions, nous verrons notamment comment lever nos propres exceptions.

 
[ Arnaud GadalJDNet
 
Accueil | Haut de page