Skip to main content

Autres mécanismes (non objet) - Le Mécanisme des exceptions

Définition : Le mécanisme des exceptions est une technique de gestion d'erreurs qui permet de transmettre une erreur en dehors du flot normal de la pile d'appel.

La gestion d'erreurs

La gestion d'erreurs se charge des défauts de programme (cas anormaux) se produisant au cours de l'exécution. Son objectif n'est pas simplement d'afficher un message pour informer d'un problème. Elle doit permettre aux parties du programme contenues dans la pile d'appel d'effectuer un traitement. Pour une gestion d'erreurs, il est nécessaire d'avoir

  • Une détection d'erreur, si condition alors il y a erreur de catégorie X. Cette portion de code détecte une condition d'erreur mais ne la traite pas. Son objectif est de signaler l'erreur au reste du code de l'application. Elle est signalée à travers une donnée particulière correspondant à la catégorie de l'erreur.
  • Un gestionnaire d'erreur, si erreur de catégorie X alors voici le traitement à faire. Un gestionnaire d'erreur définit un code de traitement pour une catégorie particulier d'erreur. Pour traiter cette erreur, les gestionnaire doit recevoir la donnée définie dans le code de détection. Une partie de programme peut définir plusieurs gestionnaires pour des catégories différentes d'erreur. Pour une catégorie d'erreur, plusieurs gestionnaires peuvent être définis dans la pile d'appel.
  • Un mécanisme de transmission de l'erreur, si indication d'erreur X alors transmettre l'exécution au gestionnaire d'erreur X. Le cours normal de l'exécution doit s'arrêter et continuer avec le code d'un gestionnaire de cette erreur. Ce gestionnaire est trouvé en remontant la pile d'appel.

Le mécanisme de transmission de l'erreur

Un moyen d'effectuer cette transmission entre la détection et le gestionnaire est d'utiliser la valeur de retour des fonctions. Mais cette transmission n'est pas automatique, elle doit être écrite par le programmeur pour chaque appel d'une fonction afin de remonter la pile d'appel. Pour avoir une transmission automatique, le mécanisme de gestion d'erreur doit enregistrer pour chaque gestionnaire d'erreur se trouvant dans la pile d'appel : la catégorie d'erreur et l'adresse de début du code à exécuter. Dés qu'une erreur est signalée, la transmission se fait par un saut ("goto") à l'adresse du début du bloc du dernier gestionnaire enregistré pour cette catégorie d'erreur.

Le mécanisme d'exception du langage Java

Il est basé sur :

  • Une exception est un objet encapsulant des informations sur l'erreur. Chaque catégorie d'erreur est représentée par une classe (donc un type)
  • La levée d'une exception provoque la rupture de séquence et transmet l'instance d'une classe d'exception. Le choix du gestionnaire se fait en fonction du type de la classe d'exception.
  • La capture d'une exception déclare le gestionnaire : le type de la classe d'exception pris en compte et le bloc de traitement. Ce bloc récupère l'instance tranmise par la levée.

Les classes d'exception

Une classe est considérée comme une classe d'exception si elle possède un lien "est-un" avec la classe java.lang.Throwable. Cette classe définit un comportement par défaut :

  • son constructeur prend en paramètre une chaîne de caractères utilisée comme message d'erreur;
  • getMessage() : message d'erreur fourni lors de l'instanciation
  • printStackTrace() : affichage des informations sur la pile d'appel.

L'API Java fournit déjà une hiérarchie de classes d'exception. Chacune de ces classes correspond à une catégorie d'erreur

java.lang.Throwable
Java.lang.Error
java.lang.AssertionError
java.lang.VirtualMachineError
Java.lang.Exception
java.lang.ClassNotFoundException
java.io.IOException
java.io.FileNotFoundException
java.lang.RuntimeException
java.lang.NullPointerException
java.lang.ArrayIndexOfBoundsException

La levée d'une exception

Le bloc de détection lève une exception grâce à l'instruction throw suivie de l'instance d'une classe d'exception

if(conditionErreur)
throw new LaClasseException("Message_d'erreur");

L'instruction throw provoque la rupture de séquence, le saut vers un gestionnaire de cette erreur.

La capture d'une exception

La capture s'effectue à l'aide d'un bloc try/catch/finally

try{
// ...
}
catch(Nom1Exception e){
// ...
}
catch(Nom2Exception e){
//...
}
catch(Nom3Exception | Nom4Exception e){
//...
}
[finally{}]

try délimite les instructions où s'appliquent la ou les captures suivantes.

catch déclare le gestionnaire d'une exception. Chaque clause catch contient un seul paramètre correspondant au type de l'exception à capture. À l'exécution, ce paramètre va référencer l'instance précisée dans l'instruction throw. Toutes les clauses catch d'un bloc try/catch/finally doivent avoir des types différents de paramètre.

finally Cette clause est optionnelle. Si elle est présente, son bloc d'instructions est systématiquement exécuté après la fin du bloc try ou du bloc d'une clause catch.

Il y a toujours une seule clause try et au moins une clause catch. Si aucune exception n'est levée dans les instructions des clauses try ou catch, l'exécution continue normalement après le bloc try/catch/finally. Par défaut, la machine virtuelle capture toutes les exceptions et affiche un message d'erreur.

Spécification de la propagation

Une exception est dite propagée par un bloc de code si cette exception n'est pas capturée dans ce bloc. Cette propagation se fait en "remontant" la pile d'appel. En Java, la clause throws permet de spécifier cette propagation dans la déclaration d'une méthode ou d'un constructeur. Cette spécification est obligatoire :

  • pour les sous-types de la classe java.lang.Exception
  • mais non sous-types de la classe java.lang.RuntimeException.

Ces exceptions sont dites contrôlées/vérifiées. Elle correspondent à la majorité des exceptions définies par l'API Java.

Pour une exception contrôlée/vérifiée, le compilateur Java provoque une erreur si le corps d'une méthode ou d'une constructeur propage (ne capture pas) cette exception sans déclaration dans la clause throws.