# Programmation Java/Exceptions

* Introduction
* La notion de machine virtuelle
* Installation
** NetBeans
** Eclipse
** Visual Studio Code
* Bases du langage
** Premier programme
** Commentaires
** Types de base
** Opérateurs
** Conditions
** Bloc de portée
** Itérations
** Tableaux
* Les classes en Java
** Membres
** Modificateurs d'accès
** Héritage
** Encapsulation
** Polymorphisme
** Classes abstraites
** Interfaces
** Classes internes
** Transtypage
** Types génériques
** Instanciation et cycle de vie
** « this »
** Objets comparables et clés
** Énumérations
** Exceptions
** Packages
* Classes de base
** Collections
** Nombre de taille arbitraire
** Tags Javadoc
** Annotations
** Entrées sorties
** Threads et synchronisation
** Méthodes natives
** Réflexion
** Regex
** JUnit
* Conclusion
* Exemples en Java
** Générer un carré magique
** Générer un triangle de Sierpiński
** XML
** Swing
*** Un premier exemple
*** Formulaire avec boutons sur image
*** Calcul de somme
*** Calcul de distance
* Annexes
** Les outils de base fournis avec le Java Development Kit
** Créer une archive Java
** Paramétrer la JVM
** Liste des mots réservés
** Débogage
** Java et les autres langages
* Introduction
* La notion de machine virtuelle
* Installation
** NetBeans
** Eclipse
** Visual Studio Code
* Bases du langage
** Premier programme
** Commentaires
** Types de base
** Opérateurs
** Conditions
** Bloc de portée
** Itérations
** Tableaux
* Les classes en Java
** Membres
** Modificateurs d'accès
** Héritage
** Encapsulation
** Polymorphisme
** Classes abstraites
** Interfaces
** Classes internes
** Transtypage
** Types génériques
** Instanciation et cycle de vie
** « this »
** Objets comparables et clés
** Énumérations
** Exceptions
** Packages
* Classes de base
** Collections
** Nombre de taille arbitraire
** Tags Javadoc
** Annotations
** Entrées sorties
** Threads et synchronisation
** Méthodes natives
** Réflexion
** Regex
** JUnit
* Conclusion
* Exemples en Java
** Générer un carré magique
** Générer un triangle de Sierpiński
** XML
** Swing
*** Un premier exemple
*** Formulaire avec boutons sur image
*** Calcul de somme
*** Calcul de distance
* Annexes
** Les outils de base fournis avec le Java Development Kit
** Créer une archive Java
** Paramétrer la JVM
** Liste des mots réservés
** Débogage
** Java et les autres langages
[ Modifier le sommaire ]
Une exception est un signal qui se déclenche en cas de problème. Les exceptions permettent de gérer les cas d'erreur et de rétablir une situation stable (ce qui veut dire, dans certains cas, quitter l'application proprement). La gestion des exceptions se décompose en deux phases :
* La levée d'exceptions,
* Le traitement d'exceptions.
En Java, une exception est représentée par une classe. Toutes les exceptions dérivent de la classe Exception qui dérive de la classe Throwable.

## Levée d'exception

Une exception est levée grâce à l'instruction throw :
Une exception peut être traitée directement par la méthode dans laquelle elle est levée dans un bloc catch, ou bien sans traitement dans la méthode, elle est envoyée à la méthode appelante auquel cas l'instruction throws (à ne pas confondre avec throw) doit être employée pour indiquer les exceptions non traitées :
Dans cet exemple, si une exception de type IOException non traitée est levée durant l'exécution de maMethode, l'exception sera envoyée à la méthode appelant maMethode, qui devra la traiter.
Certaines exceptions sont levées implicitement par la machine virtuelle :
* NullPointerException quand une référence nulle est déréférencée (accès à un membre),
* ArrayIndexOutOfBoundsException quand l'indice d'un tableau dépasse sa capacité,
* ArithmeticException quand une division par zéro ou une autre erreur arithmétique a lieu.
Celles-ci n'ont pas besoin d'être déclarées avec l'instruction throws car elles dérivent de la classe RuntimeException, une classe d'exceptions qui ne sont pas censées être lancées par une méthode codée et utilisée correctement.

## Traitement d'exception

Le traitement des exceptions se fait à l'aide de la séquence d'instructions try...catch...finally.
* L'instruction try indique qu'une instruction (ou plus généralement un bloc d'instructions) susceptible de lever des exceptions débute.
* L'instruction catch indique le traitement pour un type particulier d'exceptions. Il peut y avoir plusieurs instructions catch pour une même instruction try.
* L'instruction finally, qui est optionnelle, sert à définir un bloc de code à exécuter dans tous les cas, exception levée ou non.
Il faut au moins une instruction catch ou finally pour chaque instruction try.
Exemple :
Le bloc catch (FileNotFoundException fnfe) capture toute exception du type FileNotFoundException (cette classe dérive de la classe IOException).
Le bloc finally est exécuté quel que soit ce qui se passe (exception ou non).
Toute autre exception non capturée (telle IOException) est transmise à la méthode appelante, et doit toujours être déclarée pour la méthode, en utilisant le mot clé throws, sauf les exceptions dérivant de la classe RuntimeException. S'il n'y avait pas cette exception à la règle, il faudrait déclarer throws ArrayIndexOutOfBoundsException chaque fois qu'une méthode utilise un tableau, ou throws ArithmeticException chaque fois qu'une expression est utilisée, par exemple.

### Ne jamais ignorer une exception

Il est tentant de vouloir ignorer une ou des exceptions en la capturant pour ne faire aucun traitement et en poursuivant l'exécution, comme dans cet exemple tiré des fichiers sources de Java :
Cependant, c'est une très mauvaise pratique, car l'exception indique que les données d'entrée comportent une erreur mais l'utilisateur ou le développeur n'est pas informé. La poursuite de l'exécution aboutira alors à la production d'un résultat mauvais dont l'origine sera très difficile à remonter.
Il vaut mieux :
* retirer le bloc catch et permettre de remonter l'exception à un niveau plus haut,
* ou retransmettre l'exception avec un type plus précis indiquant le problème de manière plus détaillée.
Remonter l'exception permet un traitement approprié (correction de code, message d'erreur à l'utilisateur pour qu'il corrige les valeurs d'entrées, essayer une autre solution, ...).

## Classes et sous-classes d'exception

L'héritage entre les classes d'exceptions peut conduire à des erreurs de programmation. En effet, une instance d'une sous-classe est également considérée comme une instance de la classe de base.

### Ordre des blocs catch

L'ordre des blocs catch est important : il faut placer les sous-classes avant leur classe de base. Dans le cas contraire le compilateur génère l'erreur exception classe_exception has already been caught.
Exemple d'ordre incorrect :
L'ordre correct est le suivant :

### Sous-classes et clause throws

Une autre source de problèmes avec les sous-classes d'exception est la clause throws. Ce problème n'est pas détecté à la compilation.
Exemple :
Cette méthode ne lancera jamais d'exception de type FileNotFoundException car cette sous-classe de IOException est déjà capturée.

## Relancer une exception

Une exception peut être partiellement traitée, puis relancée. On peut aussi relancer une exception d'un autre type, cette dernière ayant l'exception originale comme cause.
Dans le cas où l'exception est partiellement traitée avant propagation, la relancer consiste simplement à utiliser l'instruction throw avec l'objet exception que l'on a capturé.
Exemple:
Une exception d'un autre type peut être levée, par exemple pour ne pas propager une exception de type SQLException à la couche métier, tout en continuant à arrêter l'exécution normale du programme :
La pile d'appel est remplie au moment de la création de l'objet exception. C'est à dire que les méthodes printStackTrace affiche la localisation de la création de l'instance.
Pour mettre à jour la pile d'appel d'une exception pré-existante (réutilisation pour éviter une allocation mémoire, ou relancer une exception), la méthode fillInStackTrace peut être utilisée :

## Catégorie d'objet lancé

Le chapitre traite des exceptions, mais en fait tout objet dont la classe est ou dérive de la classe Throwable peut être utilisé avec les mots-clés throw, throws et catch.

### Classes dérivées de Throwable

Il existe deux principales sous-classes de la classe Throwable :
* Exception signale une erreur dans l'application,
* Error signale une erreur plus grave, souvent au niveau de la machine virtuelle (manque de ressource, mauvais format de classe, ...).

### Créer une classe d'exception

Il est également possible d'étendre une classe d'exception pour spécialiser un type d'erreur, ajouter une information dans l'objet exception, ...
Exemple :
Une instance de cette classe peut ensuite être lancée de la manière suivante :
et capturée comme suit :

## Fermeture des ressources

Les objets de ressource alloue de la mémoire ou maintienne une ressource ouverte (un flux de fichier, une socket, ...). Il est important d'assurer la libération de la mémoire ou la fermeture de la ressource, quoi qu'il se passe, exception ou non. Dans le cas contraire, la ressource ne serait libérée qu'à la fin de l'application, qui peut donc cumuler les ressources ouvertes pouvant provoquer une fuite mémoire, une pénurie de ressource système, ...

### Bloc finally

La première solution pour libérer une ressource est de le faire dans un bloc finally. Celui-ci doit être précédé du bloc try contenant le code utilisant la ressource ouverte.

### Fermeture automatique

La seconde solution s'applique aux classes implémentant l'interface java.io.Closeable. La déclaration des instances de ces classes peut être employée en paramètre du mot-clé try.
Ce code est équivalent à l'exemple de la section précédente, en moins de lignes de code.
Le bloc try pour cette syntaxe peut accepter des blocs catch pour traiter des exceptions ou finally pour libérer des ressources, mais sont optionnels.

## Exceptions non capturées

Une exception lancée explicitement ou implicitement depuis une méthode peut ne pas être capturée. Dans ce cas, elle est remontée au niveau de la méthode appelante. La classe de cette exception (ou une classe parente) doit être déclarée dans une clause throws à la fin de la déclaration de la méthode appelée, à moins que la classe soit une sous-classe de java.lang.RuntimeException ou java.lang.Error.
La méthode main peut aussi déclarer des exceptions. Quand la méthode main ne capture pas une exception, celle-ci remonte à l'appelant (code interne de la JVM) qui affiche l'exception dans la console (flux d'erreur standard), et provoque donc l'arrêt de l'application si aucun thread non démon ne tourne.
Pour un thread, la méthode run des implémentations de l'interface java.lang.Runnable ne peut pas déclarer d'exceptions lancées. Cela ne l'empêche pas de remonter les exceptions non déclarées (java.lang.RuntimeException, java.lang.Error, et leurs sous-classes). Dans ce cas, le thread est interrompu et la JVM affiche l'exception dans la console (flux d'erreur standard).
Il est possible de traiter les exceptions non capturées par un thread. L'interface java.lang.Thread.UncaughtExceptionHandler définie dans la classe java.lang.Thread a une méthode uncaughtException notifiée lorsqu'un thread n'a pas capturé une exception.
Exemple d'implémentation :
Ce gestionnaire peut ensuite être assigné à différents niveaux :
* au niveau global pour tous les threads de l'application en appelant la méthode statique setDefaultUncaughtExceptionHandler de la classe java.lang.Thread :
    Thread.setDefaultUncaughtExceptionHandler(eh);
* au niveau d'un thread en appelant la méthode d'instance setUncaughtExceptionHandler :
    thread_telechargement.setUncaughtExceptionHandler(eh);
* au niveau d'un groupe de threads java.lang.ThreadGroup car cette classe implémente l'interface UncaughtExceptionHandler :
    ThreadGroup tg_telechargeurs = new ThreadGroup { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("Une exception "+e); System.out.println("a eu lieu dans le thread "+t); } }; Thread telecharge_html = new Thread(tg_telechargeurs, run_get_html); Thread telecharge_css = new Thread(tg_telechargeurs, run_get_css); Thread telecharge_js = new Thread(tg_telechargeurs, run_get_js);

## Voir aussi

* Liste des exceptions