pdf - e-book - archive - github.com

1.12  Exceptions

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 :

1.12.1  Rattraper une exception

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é.

1.12.2  Méthodes levant des exceptions

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.

1.12.3  Propagation d’une exception

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.

1.12.4  Définir une exception

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 !";
    }
}

1.12.5  Lever une exception

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);
}

1.12.6  Rattraper plusieurs exceptions

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é).

1.12.7  Finally

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);
  }
 }
}

Télécharger le fichier

1.12.8  RuntimeException

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 !