Le mécanisme des exceptions en Java (et dans d’autres langages objets) permet de gérer de façon élégante les erreurs pouvant survenir à l’exécution. Elles présentent trois avantages :
Lorsqu’une séquence d’instructions est susceptible d’occasionner une
erreur, on la place dans un bloc
try
. Comme ci-dessous :
try { /* bloc d'instructions */ }
On place juste après ce bloc un bloc
catch
qui permet de
traiter l’erreur :
try { /* bloc d'instructions */ } catch(nomErreur e) { /* Traitement de l'erreur */ }
Une exception est une erreur pouvant être rattrapée
en cours d’exécution. Cela signifie que si une erreur survient, une
exception est levée, le code du
try
est interrompu
et le code contenu dans le
catch
est exécuté. Par exemple,
try { int i = 0; while(true) { t[i++]++; } } catch(ArrayIndexOutOfBoundException e) { System.out.println("An exception has been raised."); }
Dans le code précédent l’indice
i
est incrémenté jusqu’à ce
que cet indice dépasse la taille du tableau. Dans ce cas l’exception
ArrayIndexOutOfBoundException
est levée et le code
correspondant à cette exception dans le
catch
est
exécuté.
Si vous rédigez une méthode susceptible de lever une exception, vous
devez le déclarer en ajoutant à son entête l’expression
throws <listeExceptions>
. Par exemple,
public void bourreTableau() throws ArrayIndexOutOfBoundException { int i = 0; while(true) { t[i++]++; } }
Vous remarquez qu’il n’y a pas de
try ... catch
. Cela
signifie que l’erreur doit être rattrapée dans le sous-programme
appelant. Par exemple,
try { bourreTableau(); } catch(ArrayIndexOutOfBoundException e) { System.out.println("Il fallait s'y attendre..."); }
Bref, lorsqu’une instruction est susceptible de lever une exception, vous devez soit la rattraper tout de suite, soit indiquer dans l’entête du sous-programme qu’une exception peut se propager et qu’elle doit donc être traitée dans le sous-programme appelant.
Par traiter une exception, on entend soit la rattraper tout de suite, soit la propager. Par propager, on entend laisser le sous-programme appelant la traiter. Il est possible lorsque l’on invoque un sous-programme levant une exception, de la propager. Par exemple,
public void appelleBourreTableau() throws ArrayIndexOutOfBoundException { bourreTableau(); }
On observe que
appelleBourreTableau
se contente de
transmettre l’exception au sous-programme appelant. Ce mode de
fonctionnement fait qu’une exception non rattrapée va se propager dans
la pile d’appels de sous-programmes jusqu’à ce qu’elle soit
rattrapée. Et si elle n’est jamais rattrapée, c’est la JVM, qui va le
faire.
Une exception est tout simplement une classe héritant de la classe
Exception
.
class MonException extends Exception { public MonException() { System.out.println("Exception monException has been raised..."); } public String toString() { return "You tried to do an illegal assignement !"; } }
On lève une exception en utilisant la syntaxe
throw new <nomexception>(<parametres>)
.
L’instanciation de l’exception se
fait donc en même temps que sa levée. Par exemple,
try { /* ...... */ throw new MonException(); /* ...... */ } catch(MonException e) { System.out.println(e); }
Il se peut qu’une même instruction (ou suite d’instruction) soit
susceptible de lever des exceptions différentes, vous pouvez dans ce
cas placer plusieurs
catch
à la suite du même
try
.
try { bourreTableau(); } catch(ArrayIndexOutOfBoundException e) { System.out.println("Il fallait s'y attendre..."); } catch(Exception e) { System.out.println(e); }
Notez bien que comme toute exception hérite de
Exception
, le
deuxième
catch
sera exécuté quelle que soit l’exception levée
(sauf si bien entendu le premier
catch
est exécuté).
Il est quelquefois nécessaire qu’une section de code s’exécute quoi
qu’il advienne (pour par exemple fermer un fichier). On place dans ce
cas une section
finally
.
try { /* ......; */ } catch(/* ...*/) { /* ..... */ } finally { /* ..... */ }
Par exemple,
package exceptions; class MonException extends Exception { @Override public String toString() { return "Fallait pas invoquer cette methode..."; } } public class Finally { public static void main(String[] args) { try { try { throw new MonException(); } catch (MonException e) { throw new MonException(); } finally { System.out.println("Tu t'afficheras quoi qu'il advienne !"); } } catch (Exception e) { System.out.println(e); } } }
Je vous ai menti au sujet de
ArrayIndexOutOfBoundException
, il s’agit d’une exception
héritant de
RuntimeException
qui lui-même hérite de
Exception
. Un code Java dans lequel une
RuntimeException
n’est pas traitée passera la
compilation. Par contre,
MonException
n’est pas une
RuntimeException
et doit être rattrapée !