Les Exceptions

publicité
http://www.labo-sun.com
[email protected]
Les Exceptions
GESTION D'ERREURS
Auteur : Stéphane Arnault
Version n° 2.1 – 17 avril 2017
Nombre de pages : 18
Ecole Supérieure d’Informatique de Paris
23. rue Château Landon 75010 – PARIS
www.supinfo.com
Les Exceptions - Gestion d'erreurs
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
2 / 18
Les Exceptions - Gestion d'erreurs
3 / 18
Table des matières
1. PRESENTATION ............................................................................................................................................. 4
2. TRAITEMENT DES ERREURS ..................................................................................................................... 5
2.1. GESTION D’ERREUR....................................................................................................................................... 5
2.1.1. Erreur prévue ........................................................................................................................................ 5
2.1.2. Erreur imprévue .................................................................................................................................... 5
2.1.3. Erreurs surveillées / Erreurs non surveillées ........................................................................................ 6
3. LES EXCEPTIONS........................................................................................................................................... 7
3.1. INTRODUCTION ............................................................................................................................................. 7
3.2. DEFINITION ................................................................................................................................................... 7
3.3. LES CLASSES D’EXCEPTIONS ......................................................................................................................... 8
3.3.1. La classe fille Error .............................................................................................................................. 8
3.3.2. La classe fille Exception ........................................................................................................................ 8
3.4. GESTION DES EXCEPTIONS............................................................................................................................. 9
3.4.1. Le bloc try / catch .................................................................................................................................. 9
3.5. REMONTEE DES EXCEPTIONS ....................................................................................................................... 10
3.6. LES EXCEPTIONS CHAINEES ......................................................................................................................... 11
3.6.1. Modifier l’origine d’une exception...................................................................................................... 12
3.6.2. Le mot clé finally ................................................................................................................................. 13
4. LEVER SOI-MEME DES EXCEPTIONS .................................................................................................... 14
5. CREER SES PROPRES EXCEPTIONS....................................................................................................... 15
6. LES LOGS ....................................................................................................................................................... 16
6.1. LA GESTION DES LOGS ................................................................................................................................. 16
6.1.1. La mise en place de commons-logging................................................................................................ 16
6.1.2. Les différents warning ......................................................................................................................... 16
6.2. EXEMPLE DE GESTION DE LOG AVEC COMMONS-LOGGING .......................................................................... 16
7. CONCLUSION ................................................................................................................................................ 18
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
4 / 18
1. Présentation
A l’origine, Java a été conçu dans l’optique de se définir comme un système embarqué. Ces systèmes
embarqués ou programmes, sont intégrés dans des périphériques spécialisés comme les PDA1, les
téléphones portables, et autres appareils électroménagers divers. Pour ce type d’utilisation, il parait
indispensable de prendre en compte une gestion efficace des erreurs du logiciel.
En effet, il n’est pas concevable pour beaucoup d’utilisateurs d’avoir un appareil de type téléphone,
micro-onde ou encore grille pain qui devienne hors service suite à un disfonctionnement du logiciel
intégré dans l’appareil.
Il n’est pas possible d’éliminer toute possibilité d’erreur dans nos programmes, mais nous pouvons
tout de même tenter de résoudre les problèmes en ciblant et en analysant les éventuelles erreurs de
l’application qui pourront être prévues de manière rigoureuse et systématique.
1
Personal Digital Assistant
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
5 / 18
2. Traitement des erreurs
A la suite d’une erreur à l’exécution d’un programme deux manières de gérer cette erreur sont
possibles :
2.1.Gestion d’erreur
2.1.1. Erreur prévue
Si l’erreur a été prévue par le programmeur, ce qui peut être un cas exceptionnel suite à une erreur
engendrée par un utilisateur qui entrerait une valeur trop grande, le programme doit prévoir des lignes
de code spécialement prévues pour traiter ces erreurs particulières.
2.1.2. Erreur imprévue
Selon que l’erreur était prévisible ou non, deux cas de figure possible :
Erreur qui était prévisible
Si l’erreur était prévisible ce cas de figure ne peut avoir lieu en Java car le compilateur doit détecter
toutes les erreurs et donc forcer le programmeur à tenir compte de ses erreurs. L’erreur prévisible
provient du programmeur qui aurait omis de prendre en compte certains paramètres.
Erreur imprévisible
Dans ce cas, l’erreur provient d’une lacune dans le programme et dépend des conditions dans
lesquelles le programme a été exécuté.
L’interpréteur Java (machine virtuelle) produit alors un message d’erreur et l’exécution est stoppée.
Exception qui est levé lors du RunTime, par exemple l’utilisation d’une méthode d’un objet ayant une
référence null:
package com.labo.sun;
public class Exceptions {
public static void main(String[] args) {
String var = null;
var.charAt(0);
}
}
Ce qui donne l’exception suivante :
Exception in thread "main" java.lang.NullPointerException
at com.labo.sun.Exceptions.main(Exceptions.java:7)
Remarque : L’attitude imposée au programmeur consiste à signaler l’erreur et à arrêter le
traitement.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
6 / 18
2.1.3. Erreurs surveillées / Erreurs non surveillées
Java oblige le développeur à traiter uniquement les erreurs surveillées et à les attraper. Une erreur
surveillée par le compilateur oblige le développeur à fournir le code nécessaire au traitement de cette
erreur.
Les erreurs non surveillées sont considérées comme trop graves pour que leur traitement puisse être
prévu. Le traitement de l’erreur est géré par le compilateur lui-même. Les exceptions qui peuvent ne
pas être attrapées sont des instances de la classe RuntimeException, si aucun bloc de code susceptible
de traiter l’opération n’est trouvé.
Exemple : Division par zéro, dans ce cas une erreur survient mais le compilateur ne s’en occupe pas.
public static void main(String[] args) {
int i = 10/0;
System.out.println(i);
}
Ce qui donne l’exception suivante :
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.labo.sun.Exceptions.main(Exceptions.java:6)
Un message d’erreur apparaît alors ce qui indique que l’erreur a été traitée et l’exécution est
interrompue. C’est un traitement exceptionnel et non une erreur.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
7 / 18
3. Les exceptions
3.1.Introduction
Ces erreurs sont appelées exceptions, et la gestion de ces exceptions doit être implémentée en Java.
En ce qui concerne ces exceptions, Java intègre deux principes fondamentaux :
Le compilateur doit détecter la très grande majorité des erreurs dans le but de rendre les probabilités
d’avoir des erreurs d’exécution les plus basses possibles.
Le traitement des erreurs doit être séparé du code afin de rendre celui-ci le plus lisible possible et
surtout exempt de tout message d’erreur.
La gestion des exceptions en Java est, à quelques détails près, identique à celle effectuée par le C++.
Les exceptions ont pour but d’avertir le programmeur qu’une erreur ou encore qu’un état inhabituel
s’est produit. Le contrôle du programme est alors transféré à une section de code particulière où celleci est capturée puis traitée. Grâce à cela, la gestion des erreurs est légèrement séparée du code.
Comme les erreurs sont manipulées par un mécanisme séparé, il n’est plus utile d’avoir des valeurs de
retour particulières pour les méthodes. Le contrôle d’exécution du programme peut être transmis à
n’importe qu’elle distance, depuis tout point du programme, et si on le souhaite, il peut n’être géré que
dans un seul endroit mais une erreur peut aussi être manipulée directement à sa source.
Une méthode Java doit spécifier les exceptions qu’elle ne peut pas capturer par elle-même.
De cette façon le compilateur peut être sûr que les exceptions sont bien gérées par le programme.
Avec cette manière de traitement, les informations concernant les erreurs qui peuvent être générées par
une méthode, ont la même importance (priorité) que les types de retour et arguments de la méthode.
3.2.Définition
Une exception est un signal d’erreur, c’est en fait un objet, qui est crée lorsqu'une situation anormale
se produit, pendant l'exécution du programme.
Les exceptions sont toujours issues de la classe Throwable.
Les deux sous classes Error et Exception dérivent de cette classe Throwable.
Les exceptions sont représentées par des objets qui sont des instances de la classe
java.lang.Exception et de ses classes filles.
Beaucoup de classes filles d’Exception gèrent des informations spécialisées pour différents problèmes.
Lorsqu’une erreur est rencontrée :
L’interpréteur crée un objet (à l’aide de l’opérateur new) d’une classe particulière, sous classe de la
classe Exception.
Ensuite l’opérateur recherche une portion de code qui devra être capable de recevoir l’objet créé et de
lui apporter le traitement adéquat.
Si ce n’est pas le cas, l’interpréteur Java applique lui-même le traitement : c’est le throw (remontée
d’exception). Pour trouver le code capable de traiter cet objet, l’interpréteur utilise le type de cet objet
(la classe dont il est l’instance).
Si le code est trouvé, l’objet est transmis et l’exécution se poursuit donc à cet endroit du code.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
8 / 18
3.3.Les classes d’exceptions
Hiérarchie des classes filles de java.lang.Exception et de java.lang.Error
3.3.1. La classe fille Error
La sous-classe Error représente des erreurs sérieuses de la machine virtuelle (récursivité infinie,
classe en chargement introuvable, etc…).
Les erreurs irrécupérables définies dans la classe Error du package java.lang provoquent
généralement un arrêt de l’interpréteur précédé d’un message d’erreur. Ce type d’erreur n’aura pas à
être capturé.
3.3.2. La classe fille Exception
La sous classe Exception a pour but de définir l’ensemble des exceptions pouvant être directement
gérées par le développeur. Les classes standard comme RuntimeException ou encore IOException
héritent de cette classe Exception.
La classe RuntimeException correspond aux petits incidents (envoi de message à une référence mise
à null donnera NullpointerException). Cependant on n’est pas obligé de traiter ces exceptions pour
des raisons pratiques, parce que sinon votre code java va essentiellement être consacré à la gestion
d’exceptions et ainsi, votre code utile sera réduit par rapport au code de traitement.
Toutes les exceptions dérivent de la classe Throwable. Cette classe définit deux constructeurs :
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs

Throwable()

Throwable(String)
9 / 18
La chaîne passée en paramètre est utilisée généralement pour décrire le problème représenté par
l’exception. Cette chaîne peut être obtenue par la méthode d’instance getMessage qui est héritée de la
classe Throwable.
La classe Throwable définit aussi la méthode d’instance printStackTrace qui a pour but d’afficher
l’exception et l’état de la pile d’exécution2 au moment de son appel.
Pour les exceptions dont la classe héritée est RuntimeException, il n’est pas obligatoire de gérer ses
exceptions. Par contre toutes les exceptions sous-classes de Exception devront utiliser le try/catch,
faute de quoi le compilateur refusera de compiler.
Voici une méthode correcte (en terme de syntaxe) qui n’exige pas de gestion :
Public void maMethode(){
throw new Error(“Mon error …” );
}
3.4.Gestion des exceptions
Un objet Exception est créé par l’interpréteur à l’endroit où l’erreur s’est produite. Cet objet peut
contenir des informations concernant l’exception mais aussi une pile d’exécution pour permettre le
déboguage.
L’objet est alors passé en argument au bloc chargé du traitement de l’erreur. L’objet Exception est
envoyé par l’intermédiaire du mot clé throw puis capturé à un autre endroit du code avec le mot clé
catch où l’exécution du code reprend.
3.4.1. Le bloc try / catch
Le mécanisme
Une exception est un objet qui est instancier lors d’un incident, on dit alors que l’exception est levée.
Le traitement du code de la méthode est interrompu et l’exception est propagée à travers la pile
d’exécution de la méthode appelée vers la méthode appelante.
Si aucune méthode ne capture l’exception, elle remonte jusqu'à la méthode du fond de la pile
d’exécution. Une indication d’erreur est donnée à la fin de l’exécution.
Le bloc try/catch a pour but de capturer les exceptions.
Employer les bons mots…
Lorsque l’interpréteur génère une exception, on dit qu’il lève une exception.
Le fait de faire disparaître cette exception s’appelle la capturer.
Le bloc catch s’appelle également handler d’exception.
2
Liste des méthodes en cours d’exécution
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
10 / 18
try cerne un bloc d’instructions pour lequel on voudra capturer les exceptions qui pourraient être
levées. Dans le cas où plusieurs exceptions pourraient être produites, l’exécution du bloc cerné par le
try sera interrompue à la première exception levée.
catch va quant à lui définir l’exception à capturer en référençant tout d’abord l’objet de l’exception
par un paramètre puis le bloc à exécuter si une capture avait lieu.
L’exception lancée dans le bloc est attrapée par le catch qui prend pour paramètres un objet du type de
l’exception lancée.
Exemple :
catch (RuntimeException e)
Différencier les exceptions avec un catch :
try {
// code qui peut engendrer une exception
} catch (RuntimeException e){
System.out.println(e.getMessage());
}
Dans cet exemple toutes les instructions issues de la classe RuntimeException (ou héritées de cette
classe) sont capturées dans le bloc qui suit le catch.
Pour différencier les possibilités d’erreurs multiples, il faut créer plusieurs clauses catch.
try {
// code qui peut engendrer une exception
} catch (IndexOutOfBoundsException e) {
// gestion des IndexOutOfBoundsException
} catch (RuntimeException e) {
// gestion des RuntimeException
} catch (ArithmeticException e) {
// gestion des ArithmeticException
}
L'ordre des trois blocs catch est très important car si les trois ne sont pas dérivés d'une même classe
Exception, il faut placer les blocs catch en fonction de leur importance (du cas le plus précis au plus
général). Ex : ArithmeticException est une classe dérivée Exception. Le bloc catch gérant les
ArithméticException devrait être placé avant celui de Exception.
3.5.Remontée des exceptions
Une exception levée est propagée à la méthode appelante ; l’exception remonte jusqu’à ce qu’elle
puisse être capturée ou qu’elle arrive au niveau le plus haut, ce qui aura pour conséquence directe de
provoquer une erreur d’exécution.
Lorsqu’une première méthode appelle une seconde méthode intégrée dans une zone try/catch de cette
première méthode, et que cette seconde méthode appelle une troisième méthode qui lève une
exception, cette dernière méthode ne possédant pas de bloc try/catch, l’exception est renvoyée au
niveau supérieur, à savoir la seconde méthode qui elle non plus ne capture pas. L’exception est
finalement renvoyée à la première méthode. La première méthode va capturer cette exception grâce à
sa zone try, puis elle va être traitée dans sa zone catch.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
11 / 18
Dans cet exemple, on laisse le code appelant gérer l’exception que la méthode a déclenchée. Pour cela
on a défini que la méthode pouvait lever une exception, le code pouvant déclencher l’exception utilise
le mot throws pour déclarer l’exception. Dans ce cas la méthode n’a pas besoin de gérer l’exception
qu’elle a déclenchée.
3.6.Les exceptions chaînées
Une exception possède toujours une cause qui peut-être une exception ou nulle.
Ceci nous permet de remonter à la source du problème et ainsi le programmeur peut là corriger.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
12 / 18
Application
Demande d’une icône
pour l’affichage
GUIException
CAUSE
Bibliothèque d’interface
graphique
Lecture de la base
contenant le fichier
IOException
Bibliothèque d’accès aux fichiers
graphique
Puisque certaines exceptions pourront être susceptibles de remonter de très loin, il sera intéressant
d’être capable de déterminer d’où ces exceptions ont été levées.
La méthode printStackTrace() a pour but de récupérer la trace empilée de l’exception. Cette trace
empilée permet de retrouver la méthode d’origine où a été levée l’exception mais aussi permet de voir
toutes les méthodes qui ont suivi pour atteindre cette méthode initiale.
try {
// instructions pouvant générer une erreur
} catch (Exception e) {
e.printStackTrace(System.err);
}
Il est possible d’indiquer plusieurs types d’exceptions en séparant leurs noms par des virgules.
void exemple(String s) throws IOException, InterruptedException {
}
3.6.1. Modifier l’origine d’une exception
Lorsqu’une exception est détectée, l’interpréteur indique que cette exception s’est produite dans la
ligne du bloc try et non dans la méthode ou l’exception s’est réellement lancée. En effet le handler ne
se préoccupe ni de vérifier le contenu de l’exception ni sa provenance.
Pour obtenir un résultat différent, Java propose deux méthodes qui vont permettre de modifier soit
l’origine de l’exception soit son type :
Afin de pouvoir retrouver l’origine exacte ou le renvoi a été effectué, il faut utiliser la méthode
fillInStackTrace().
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
13 / 18
Une autre façon de modifier l’exception est de changer son type. Pour cela on devra avoir recours au
sur-casting :
catch (IndexOutOfBoundsException e) {
System.err.println("Erreur");
throw (RuntimeException) e;
}
3.6.2. Le mot clé finally
Il est utilisé après un bloc try/catch. Il délimite une ou plusieurs actions importantes devant être
exécutées même si une exception venait à être déclenchée et que le programme s'arrêtait.
try {
// code suceptible de déclencher une exception
} catch (Exception e) {
// gestion de l'exception
} finally {
// code toujours exécuté que l'exception ait été déclenchée
// ou non dans le bloc try
}
En effet, lorsqu'on a du ménage à faire avant de quitter une méthode, pour éviter la duplication de
code dans chaque zone de catch, on utilise ce mot clé (Exemple : ouverture d'un fichier devant être
refermé même si une erreur à été rencontrée).
Si des instructions sont exécutées dans le bloc catch, les instructions du bloc finally seront exécutées
après. Si le bloc catch ne gère pas l’exception, le bloc finally va être exécuté avant que l’exception ne
soit remontée à un niveau supérieur.
Enfin pour exécuter uniquement des opérations de nettoyage, le bloc catch peut être retiré et donc
seuls les blocs try et finally sont utilisés.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
14 / 18
4. Lever soi-même des exceptions
Il est possible d’utiliser le mot clé throw dans la création de messages d’erreurs personnalisés. Ce mot
clé indiquera que quelque chose ne s’est pas effectuée normalement.
Il est utilisé pour avertir l’utilisateur en déclenchant une exception lorsque par exemple un mot
incorrect est tapé.
if (!testWord.equals("")) {
System.out.println("Test OK");
} else {
throw new Exception("Test erroné");
}
On peut, de cette manière la, gérer l’exception levée dans une autre partie du code, séparant ainsi
complètement le test et l’action en conséquence.
Dans cet exemple, nous générons une instance de la classe Exception. Cela peut cependant être
problématique, sachant qu’un catch intermédiaire à la gestion de cette action pourrait l’attraper. Il est
donc le plus souvent nécessaire de redéfinir soi-même sa propre exception, comme nous allons le voir
dans le chapitre suivant.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
15 / 18
5. Créer ses propres exceptions
La meilleure méthode pour lever ses exceptions est de dériver ses classes d'exceptions à partir de la
classe Exception. Cela va permettre au compilateur de vérifier qu'une exception est capturée ou
déclarée de manière correcte dans le programme.
Ceci permet d’avoir ses propres types d’exceptions dans son programme. Cela permet donc
principalement de personnaliser la gestion de vos erreurs (enregistrer les erreurs dans un fichier texte
par exemple).
Exemple de programme:
// Classe héritant de la classe Exception
public class MonException extends Exception {
// Constructeur de la classe MonException
public MonException(String s) {
super(s);
// Constructeur de la sous classe
}
}
class ExceptionPerso {
public static void main(String[] args) {
try {
System.out.println("On essaye un affichage");
function();
} catch (MonException e) {
System.out.println(e.getMessage);
}
}
static int function() throws MonException {
throw new MonException("Exception");
}
}
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
6.
16 / 18
Les Messages de log
6.1.La gestion des logs
Lorsqu’une gestion des évènements est mise en place pour pouvoir retracer assez rapidement un
problème, la mise en place d’une gestion par logs permet de sauvegarder et de définir des niveaux de
priorité sur des évènement ou des exceptions. Ce qui permet de déterminer efficacement les exceptions
à l’origine du problème selon les niveaux de priorité qui sont les suivant pour commons-logging:
 Trace (Moins grave)
 Info
 Warn
 Error
 Fatal (Plus grave)
6.1.1. La mise en place de commons-logging
L’utilisation d’une implémentation de Log qui est LogFactory permet de mettre en place notre gestion
des logs :
static Log log = LogFactory.getFactory().getInstance(MaClasse.class);
Avec la méthode getInstance(Class class) ou getInstance(String name) on défini la classe qui va être
surveillée.
6.1.2. Les différents warning
Comme dit précédemment, nous avons plusieurs niveaux de logs, ces niveaux vont permettre de
répondre à nos besoins, ici lors de la gestion des erreurs, on peut déterminer si une exception est grave
ou non, si l’on souhaite afficher des infos de débugguage etc..
Dans les résultats affichés, nous avons plusieurs informations tel que l’heure, la date la méthode, le
package et le message personnalisé.
15 sept. 2006 14:42:13 com.labosun.MaClasse
INFO: Information message
15 sept. 2006 14:42:13 com.labosun.MaClasse
ATTENTION: Advertice message
15 sept. 2006 14:42:13 com.labosun.MaClasse
GRAVE: Error message
15 sept. 2006 14:42:13 com.labosun.MaClasse
GRAVE: Fatale error
<init>
<init>
<init>
<init>
6.2.Exemple de gestion de log avec commons-logging
try{
throw new Exception("Mon exception de test");
}catch(Exception e){
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Les Exceptions - Gestion d'erreurs
e.printStackTrace();
//Ici on à tous les logs à titre de démo
log.trace("Traced message");
log.info("Information message");
log.warn("Advertice message");
log.error("Error message");
log.fatal("Fatale error");
}
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
17 / 18
Les Exceptions - Gestion d'erreurs
18 / 18
7. Conclusion
Nous avons vu qu’il existe des exceptions qu’il est nécessaire de traiter et d’autre qui sont gérées par
la JVM.
Grâce à commons-logging, nous avons aussi vu qu’il était possible de gérer les niveaux de log dans
une application et ainsi mettre en place un débugguage rapide.
http://www.labo-sun.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Téléchargement