MIM1
TD 4 de POOGL
Exception

Vincent BOUDET
Bureau 343 (84-70)
email vboudet@ens-lyon.fr

23 Janvier 2000

Ce TD est volontairement plus cours, afin de parler des projets en fin de séance.

A   Pourquoi gérer les erreurs ?

En informatique, la gestion des erreurs est une préocuupation majeure. On doit dsouvent gérer des erreurs telles que la division par 0, l'accès à une zone mémoire interdite, etc. On doit se soucier des erreurs provoquées par le non-respect des procédures normales d'utilisation. On doit également prendre en compte l'apparition d'événements inopinés, comme un disque plein, une disquette non présente, une erreur de frappe, etc. De plus, la gestion fine des erreurs facilite grandement la mise au point d'un programme.

Dans les langages structurés classiques, il est habituel d'utiliser les valeurs retournées par les fonctions comme code d'erreur. La fonction appelante se charge alors de traiter les différents cas d'erreur. Le code est alors particulièrement peu lisible, car le deroulement du programme n'est pas saré du traitement des erreurs.

B   Fonctionnement des exceptions

Java, comme beaucoup de langages récents, utilise les exceptions pour gérer les erreurs ou les situations inhabituelles.Les exceptions sont des objets créés lors de situations d'erreurs et qui sont traités dans des sections réservés à cet effet.

Concrètement, quand le programme détecte une situation anormale ou une erreur il lève throw une exception. La levée d'une exception est nécessairement inscrite dans un bloc d'essai (try), elle provoque instantanément la sortie du bloc concerné et doit être capturé dans un bloc catch

C   Exemple

import java.io.*;
public class LireDouble
{

  public static void main(String[] argv)
  {
    String ch;
    double x;
    BufferedReader fluxEntree;
    fluxEntree =  new BufferedReader(new InputStreamReader(System.in));
    try 
    {
      ch = fluxEntree.readLine();
      x = Double.valueOf(ch).doubleValue();
      System.out.println(``Double lu : `` +x);
    }
    catch (Exception e)
    {
      System.out.println(``Erreur de lecture d'un double:'' + e);
      System.exit(1);
    }
  }
}

D   Lever une exception

Dans le pragrahe précédent, l'exception avait été levée par une méthode d'une classe de la bibliothèque Java, donc de façon invisible pour le programmeur. Pour lever soi même une exception on utilise l'instruction throw.
  throw newIllegalAccesError(``Acces interdit à la méthode Toto.bidule()'');

E   Créer une classe d'exception

On peut créer des sous-classes de Exception ou d'une de ses sous-classes. Par exemple :
import java.io.*;
public class LectureErreur extends Exception
{
  LectureErreur()
  {}

  LectureErreur(String message)
  {
    super(message);
  }
}
On peut alors l'utiliser de la manière suivante :
import java.io.*;
public class ES
{
  public static void main(String[] argv) throws LectureErreur
  {
    String ch='''';
    BufferedReader fluxEntree;
    fluxEntree =  new BufferedReader(new InputStreamReader(System.in));
    try 
    {
      ch = fluxEntree.readLine();
      x = Double.valueOf(ch).doubleValue();
      System.out.println("Double lu : " +x);
    }
    catch (Exception e)
    {
      throw new LectureErreur(``Erreur de lecture d'un réel double'');
    }
  }
}
La méthode appelante va pouvoir traiter cette erreur en prenant en compte le contexte dans lequel elle est survenue. Pour qu'une méthode puisse déléguer le traitement d'une exception à une méthode appelante, elle doit le signaler par une clause throws dans son en-tête. Pour qu'une exception soit controlée, il faut qu'elle soit déclarée par throws ou capturée par catch.

F   Ajout de champ

L'utilisateur a parfois besoin de renseignements complémentaires. On aimerait par exemple savoir quelle chaine de caractères a été lue.
import java.io.*;
public class LectureErreur extends Exception
{
  String chaineLue = null;
  LectureErreur()
  {}

  LectureErreur(String message)
  {
    super(message);
  }
  
  LectureErreur(String message, String chaine)
  {
    super(message);
    this.chaineLue=chaine;
  }

  String toString()
  {
    String ch;
    if (chaineLue != null )
    {
      ch = getMessage() + ``\n Chaine lue ayant provoquée l'erreur : ``;
      ch = ch + chaineLue;
    }
    else
      ch = getMeassge();
    return ch;
  }
}

G   Finally

L'instruction try ... catch peut comporter une clause finally qui sera executée dans tous les cas. Cette clause est peu utilisée, elle sert généralement à fermer les flux ouverts dans des opérations d'entrées-sorties.

H   À vous

H.1   Tampon de nombres entiers

Créer une classe TamponEntiers qui contient un champ de type int[]. Il a une capacité initiale communiquée en argument du constructeur. Quand le tableau est saturé (pensez aux exceptions), la méthode agrandir() construit un nouveau tableau de capacité supérieure. Cette classe devra comporter les méthodes suivantes :

H.2   SaturationMemoireException

Créer une classe SaturationMemoireException étendant la classe Exception. On la dotera d'un constructeur vide et d'un constructeur prenant une chaine comme argument afin de donner des précisions sur la nature des circonstances ayant provoqué la levé de l'exception.

Les tampons TamponEntiers peuvent provoquer un arrêt brutal du programme lors de l' appel à la méthode agrandir() quand la quantité de mémoire disponible est insuffisante. Capturer l'erreur de type OutOfMemoryError qui peut survenir dans la méthode agrandir() et lever alors une exception de type SaturationMemoireException. Elle sera propagée jusqu'à la méthode ajouter() afin que l'utilisateur ait la possibilité d'imprimer le travail en cours. Tester cette nouvelle classe TamponEntier en ajoutant des nombres entiers jusqu'à provoquer la saturation de la mémoire.

H.3   La factorielle

Écrire un programme simple qui calcule la factorielle d'un nombre donné sur la ligne de commande.

À partir de ce programme simple, modifiez le en utilisant des classes d'exception pour rattraper les erreurs suivantes : Dans les deux premiers cas, une exception est signalée. Dans les deux derniers cas, le résultat est faux.

Vous devez modifier le programme pour que, dans chacun de ces cas, l'erreur soit précisée à l'utilisateur. Dans le premier cas, on souhaite que le programme affiche par exemple : Indiquez le nombre d'entiers sur la ligne de commande et si le paramètre indiqué est -4 :
-4 est négatif : la factorielle n'est pas définie. 

This document was translated from LATEX by HEVEA.