Aller au contenu

Exceptions

Qu’est ce qu’une Exception ?

Les Exceptions sont instanciées, lorsque la JVM détecte des conditions anormales.

exceptions01.png

Une exception est la conséquence de toute condition anormale. Java étant un langage objet, les exceptions sont représentées par des sous-classes de la classe java.lang.Exception. Java fournit un modèle grâce auquel la gestion des exceptions se fait par la compréhension de la hiérarchie de la classe Exception.

Exemples d'exceptions diverses :

La Classe Error :

Une erreur est une condition qui empêche le programme de se terminer. Les erreurs surviennent à l'exécution et ne sont généralement pas gérées par le mécanisme d'interception des exceptions. Les erreurs provoquent la fin du programme et généralement les programmeurs ont très peu de moyens de contrôle sur elles. Par exemple :

Il existe 2 types (sous-classes) d'Exceptions :

RuntimeException :

RuntimeException est une classe abstraite qui définit un ensemble de conditions pouvant survenir n'importe où dans un programme.

Par exemple :

Le compilateur java (javac) ne force pas la gestion des RuntimeException dans le programme (vous pouvez les ignorer !).

C'est la raison pour laquelle on en parle comme étant des Exceptions non contrôlées. Bien que ce type d'Exception peut être évité par une programmation correcte, on peut l'intercepter comme toutes les autres Exceptions.

Exceptions contrôlées :

Les autres Exceptions peuvent se trouver dans tous les package java. Certaines sont définies dans le package java.lang, comme la classe InterruptedException utilisée par les Thread en veille.

D'autres sont définies dans les package java.net ou java.io et sont générées lors de problèmes de connection réseau, de tentative d'accès à un fichier indisponible. Vous pouvez aussi créer vos propres Exceptions et utiliser les mêmes mécanismes d'interception.

Il suffit de créer une classe qui hérite de la classe Exception et de créer les constructeurs adéquats.

Mécanisme des Exceptions

Une erreur détectée à l'exécution provoque la génération d'un objet de type Exception. L'exécution se débranche de son déroulement normal et l'objet Exception remonte à travers la pile des méthodes appelantes, jusqu'à la rencontre d'une portion de code pouvant l'intercepter.

Nous avons ensuite 2 possibilités :

Illustration :

**Les différents traitements d'une Exception ** :

Il y a 4 possibilités :

Ignorer l'Exception :

Une RuntimeExceptio peut tout simplement être ignorée. Sans action spécifique, la méthode dans laquelle survient une exception, s'arrête immédiatement. Elle propage ensuite l'erreur à la méthode appelante. Si cette méthode appelante ignore l'Exception, cette dernière est remontée à travers la pile des différentes méthodes appelantes, jusqu'à ce que le programme s'arrête en affichant un message d'erreur standard. On peut éviter cela par une programmation soignée.

Intercepter l'Exception :

Si une méthode est susceptible d'intercepter une Exception contrôlée, cela est indiqué explicitement par la déclaration throws. Par exemple, la méthode read() de la classe FileInputStream est déclarée comme ceci :

public int read(byte[] b) throws IOException

Cette déclaration indique au compilateur et à l'utilisateur de cette méthode qu'elle est susceptible de lever une exception IOException. Cette exception entre dans la catégorie des exceptions contrôlées et ne peut être ignorée.

il faut :

Pour intercepter une exception, il suffit de placer le code susceptible de lever cette exception (généralement l'appel d'une méthode possèdant une clause throws ) dans un bloc try/catch comme dans l'exemple ci-dessous :

String nomFichier = "fichierApprenants.txt";
try
{
 // code succeptible de lever une Exception
FileInputStream f1 = new FileInputStream(nomFichier);
int longueurFichier = f1.available();
// lecture du fichier
byte[] readBuffer = new byte[longueurFichier];
f1.read(readBuffer);
// fermeture du fichier
f1.close();
...
}
catch(IOException e)
{ // action à mener si une Exception survient
System.out.println("Erreur lors de la lecture du fichier");
}

Le rôle du bloc try/catch est d'intercepter une exception et de la corriger afin qu'elle n'interfère pas au bon déroulement du programme. Une exception peut potentiellement surgir à l'intérieur du bloc try. Dans ce cas, le contrôle est immédiatement passé au bloc catch qui gère l'exception.

Intercepter des Exceptions multiples :

Vous pouvez mettre en place l'interception de différents types d'exception. Dans ce cas, il suffit d'ajouter plusieurs bloc catch , chacun de ces blocs traitant une exception spécifique.

On peut aussi les mettre dans un seul bloc catch en les séparant par un ou avec ** **

Chaque bloc catch interceptera les exceptions de la classe spécifiée en paramètre, ainsi que des sous-classes.

S'il existe une relation d'héritage entre les 2 types d'exception à capturer, il faut placer en priorité le bloc catch le plus spécialisé avant le bloc catch le plus général.

Voici un exemple de code ci-dessous :

String nomFichier = "fichierApprenants.txt";
try
{
FileInputStream f1 = new FileInputStream(nomFichier);
int longueurFichier = f1.available();
byte[] readBuffer = new byte[longueurFichier];
f1.read(readBuffer);
...
}
catch(FileNotFoundException e)
 {
System.out.println("Fichier " + nomFichier + " non trouvé !");
}
catch(IOException e)
 {
System.out.println("Erreur lors de la lecture du fichier");
}

Utilisation du bloc finally :

Dans un bloc try, si aucune exception n'est levée, toutes les instructions du bloc try sont exécutées. Par contre, si une instruction génère une exception, les lignes de codes suivantes ne seront pas exécutées.

Le bloc finally permet d'écrire du code, qui doit être exécuté dans tous les cas, qu'il y ait ou non génération d'exception dans le bloc try. Les 2 scénari les plus courants utilisant le bloc finally sont :

A. La méthode propage toutes les exceptions, par exemple parce qu'elle n'a pas de bloc catch. Dans ce cas, le traitement standard est proprement séparé de la gestion des exceptions.

Voici un exemple de code :

try {

}
finally { // exemple : fermeture de fichiers}

B La méthode gère l'exception et la repropagation

try {
}
catch (ExceptionA e) {
throw new ExceptionB()
}

finally{
// exemple : fermeture de fichiers
}

Note : le seul cas dans lequel le bloc finally n'est pas exécuté est lorsque la méthode System.exit() est exécutée au préalable.

Plus de détails sur la documentation officielle.

Propager l'exception à la méthode appelante :

Illustration :

Explication du graphique ci-dessus :

Lors de l'exécution de la méthode3(), il y a instanciation d'un objet de classe d'ExceptionA.

La directive throw va déclencher le mécanisme d'exception : remontée de l'objet ExceptionA dans la pile des méthodes appelantes, jusqu'à la rencontre d'un bloc try/catch.

La méthode3() et la méthode2() ne contiennent pas de bloc try/catch permettant d'intercepter l'ExceptionA. Leur déclaration doit uniquement contenir une directive throws, pour signaler qu'elles sont susceptibles de lancer l'ExceptionA. C'est au niveau de la méthode1(), que l'interception de l'ExceptionA sera effectuée.

Le regroupement du code de gestion des exceptions en un lieu précis (exemple : dans la méthode1()) permet d'avoir du code plus propre.

Intercepter et repropager une Exception :

Il est possible d'intercepter une exception dans un bloc try/catch, puis de la repropager.

La syntaxe de cette technique est montrée ci-dessous. Avec ce code, vous pouvez distribuer votre gestion d'exceptions. Il peut y avoir un premier niveau de traitement en première instance, puis transmission à un niveau d'appel supérieur pour une poursuite du traitement de l'exception.

public uneMethode() throws UneException
{
try
{
// code pouvant propager UneException
}
catch(UneException e)
{
// Code de gestion d'une Exception 
throw e;
}
}

Créer votre propre Exception :

La possibilité de créer vos propres exceptions est un point fort du langage java. Généralement vous créez une exception controlée. Pour cela, il suffit d'étendre la classe Exception :

public class MonException extends Exception
 {

public MonException(String message)
 { // laissons tout le travail à la classe Exception
 super(message);
 }
 public MonException()
 { // Il est possible de juste définir un message par défaut
 super("Une Exception \"MonException\" vient de survenir ...");
 }

}

Au final, votre exception affiche un message approprié lorsque survient un problème. Les constructeurs de la classe Exception sont prévus pour permettre l'affichage d'un message lorsque l'exception survient.

Cependant, il faut savoir se souvenir que les constructeurs ne sont pas hérités, vous devez donc utiliser l'instruction super() dans le constructeur de votre classe MonException pour bénéficier de cette caractéristique.

Propager votre Exception :

Nous avons vu que la directive throw permet de déclencher le mécanisme d'exception. Remontée de l'objet MonException dans la pile des méthodes appelantes, jusqu'à la rencontre d'un bloc try/catch pour la traiter.

public class MaClasse
 { // méthode succeptible de lever une exception MonException

public void methode()
 throws MonException
 { ...// traitement
 ...
 // on teste si condition anormale et on lève une exception
 // si nécessaire
 if (codeErreur != 0)
 throw new MonException();
 }

}

Résumé de la gestion des exceptions et redéfinition des méthodes :

Une méthode redéfinie peut propager :

public void test() throws ExceptionB => redéfinit => public void test() throws ExceptionA

ExceptionB => extends => ExceptionA

Résumé de la découverte des exceptions :

2 types d'Exceptions :

4 traitements possibles d'une Exception :

Création d'une Exception spécifique, sous-classe de la classe Exception

Liens et ressources

Les exceptions sont des classes qui héritent toutes de la classe Exception, par exemple FileNotFoundException :

https://docs.oracle.com/javase/7/docs/api/java/io/FileNotFoundException.html.

Elles héritent à travers Throwable de méthodes pratiques comme :

Plus de détails sur la documentation officielle.