Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Introduction à la gestion des exceptions

Aspects avancés sur la définition d'interfaces Mise en oeuvre d'une classe d'exception



Accès rapide :
La vidéo
Qu'est qu'une exception ?
On traite l'exception.
Le mot clé try.
Le mot clé catch.
Le mot clé finally.
Quelques exceptions.
Quelques méthodes utilisables sur les exceptions.
On relaye l'exception.
Le mot clé throws.

La vidéo

Cette vidéo vous présente les concepts de base du traitement d'exception en Java. Une exception java représente un état « exceptionnel » d'exécution de votre programme : une erreur. Les mots clés try, catch, throw et throws vous sont présentés.


Introduction à la gestion des exceptions

Qu'est qu'une exception ?

Avant de rentrer dans les détails syntaxiques, je vais essayer de répondre à une première interrogation : qu'est qu'une exception ? Pour faire simple, une exception est une erreur produite durant l'exécution de votre programme. Sémantiquement parlant, le terme d'exception a été retenue car une erreur est censée être exceptionnelle : c'est n'est pas le mode de fonctionnement nominale de votre application.

dans certains cas, les développeurs utilisent le mécanisme d'exception pour représenter autre chose qu'une erreur (un cas de fonctionnement normal de l'application), mais ce type d'utilisation reste relativement marginal.

La chose la plus importante à comprendre c'est qu'en cas de déclenchement d'exception (d'erreur) le programme passe dans un mode d'exécution particulier : il faut qu'il trouve un gestionnaire d'erreur (un bloc d'instruction try / catch). Analysons le programme suivant. Via l'appel à la méthode Math.random, ce programme a une chance sur trois de déclencher une exception (à cause de la division par 0, qui rappelons le, n'est pas autorisée).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
package fr.koor.exceptions;

public class TestException {

    public static void method3() {
        System.out.println( "BEGIN method3" );
        int divisor = (int) (Math.random() * 3);
        int value = 1 / divisor;
        System.out.println( "Value == " + value );
        System.out.println( "END method3" );
    }

    public static void method2() {
        System.out.println( "BEGIN method2" );
        method3();
        System.out.println( "END method2" );
    }
    
    public static void method1() {
        System.out.println( "BEGIN method1" );
        method2();
        System.out.println( "END method1" );
    }

    public static void main(String[] args) {
        System.out.println( "BEGIN main" );
        method1();
        System.out.println( "END main" );
    }

}
Exemple de déclenchement d'exception (via une division par 0)

Comme vous le constatez, ce programme met en oeuvre une chaîne d'appels de méthodes. Bien entendu, le point d'entrée est le main. Puis il invoque method1 qui invoque à son tour method2 et qui finit par invoquer method3. A chaque niveau on trace l'entrée dans la méthode ainsi de la sortie. Comme indiqué précédemment, là ou les choses se corsent, c'est en ligne 8, car on produit une division par un entier qui peut valoir 0. Deux issues sont possibles pour ce programme.

Soit la valeur calculée aléatoirement vaut 1 ou 2 et dans ce cas, la division se passe correctement. Du coup, l'exécution du programme se passe de manière traditionnelle : voici les résultats affichés sur la console.

$> java fr.koor.exceptions.TestException
BEGIN main
BEGIN method1
BEGIN method2
BEGIN method3
Value == 0              ( ou 1, si divisor == 1)
END method3
END method2
END method1
END main$> 

Soit la valeur calculée aléatoirement vaut 0 et dans ce cas une exception est déclenchée. Une fois l'exception produite (on dit aussi que l'exception est levée) le système se met à la recherche d'un bloc de traitement d'erreur (un bloc try / catch). Le souci, c'est qu'il n'y a pas de tel bloc dans la méthode method3 : en conséquence l'exécution de la méthode est interrompue, et on se retrouve en ligne 15. Toutes les variables locales définis par method3 (ainsi que les éventuels paramètres de la méthode) sont détruites (on a dépilé au niveau de la stack). Mais nous sommes toujours en mode « exception levée » et donc le système cherche toujours à localiser un bloc try / catch. Il n'y en a pas non plus dans la méthode method2, donc on abandonne l'exécution de cette méthode et on dépile encore une fois. On se retrouve en ligne 21. Toujours pas de bloc try / catch. On sort aussi de cette méthode et on se retrouve en ligne 27. Toujours pas de try / catch et du coup on sort de la méthode main. Et là me direz-vous ?

Et bien, le programme est terminé ! La JVM a récupéré l'exception et elle l'affiche sur la console, mais après elle rend simplement la main. Le fait d'avoir suspendu l'exécution de toutes les méthodes garanti qu'aucun affichage de type END methodX ne sera produit. Voici un exemple d'exécution en cas de déclenchement d'exception.

$> java fr.koor.exceptions.TestException
BEGIN method1
BEGIN method2
BEGIN method3
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at fr.koor.exceptions.TestException.method3(TestException.java:8)
    at fr.koor.exceptions.TestException.method2(TestException.java:15)
    at fr.koor.exceptions.TestException.method1(TestException.java:21)
    at fr.koor.exceptions.TestException.main(TestException.java:27)
$> 

Donc c'est clair, il faut traiter l'erreur si vous ne voulez pas que votre programme s'arrête prématurément.

On traite l'exception.

Si l'on décide de traiter une exception, il nous faut alors définir un certain nombre de blocs d'instructions. Pour ce faire, trois mots clés sont à notre disposition : try, catch, finally. Nous allons donc étudier chacun de ces mot clés en détail.

Le mot clé try.

Ce mot clé permet de spécifier une section de code sur laquelle on s'attend qu'une exception (une erreur) soit levée. La syntaxe est simple on place le mot try, une accolade ouvrante, la section de code et, enfin, une accolade fermante.

Le mot clé catch.

Celui-ci, sert à spécifier le code à exécuter pour une exception (ou une catégorie) donnée. Il suffit alors de faire suivre le mot catch d'une parenthèse ouvrante, d'un type exception (une classe) du nom qu'on lui donne (tout comme un paramètre de fonction), d'une parenthèse fermante, et du code associé placé entre accolade.

Le mot clé finally.

Enfin, le mot clé finally permet d'introduire un code de traitement d'exception, qui sera de toute manière exécuté. Vous pouvez omettre le bloc finally.

 
try {
    // des lignes de code susceptible
    // de lever une exception
}
catch (IOException e) {
    // traitement de l'exception de type IO
}
finally {
    // traitement plus général
}

Quelques exceptions.

Le tableau suivant vous propose quelques exemples d'exceptions que vous pouvez traiter.

Exception
IOException
NullPointerException
OutOfMemoryException
ArithmeticException
ClassCastException
ArrayIndexOutOfBoundsException
negativeArraySizeException

Quelques méthodes utilisables sur les exceptions.

Le tableau suivant vous propose quelques méthodes applicables sur des objets dérivés de la classe Exception.

String toString()
void printStackTrace()

On relaye l'exception.

Maintenant, le problème est de savoir ce que l'on doit faire d'une exception que l'on aurait pas su traiter. Dans ce cas, il faut alors la relayer à la méthode appelante. Plus généralement, si une méthode est susceptible de lever une exception, et si celle-ci ne peut la traiter, elle se doit de prévenir le système qu'elle relaye cette tâche. Pour ce faire on utilise le mot clé throws.

Le mot clé throws.

Ce mot clé permet d'avertir le système qu'une certaine catégorie d'exception ne seront pas traitée en local (dans l'exemple suivant, l'ensemble des exceptions liées aux entrées/sorties).

 
void fonction throws IOException {
    // . . .
}

Le problème est de savoir ce qu'il se passe, si une exception est levée et qu'elle n'est traitée par aucune fonction. Dans ce cas, c'est la JVM qui la traite et affiche sa représentation sous chaîne de caractères (méthode toString appelée). Puis, le système repart la ou il en était.



Aspects avancés sur la définition d'interfaces Mise en oeuvre d'une classe d'exception