Exceptions Java

Exceptions Java

Téléchargez ici le code source.

Objectifs

  • Savoir quand utiliser les RuntimeException ou les Exception Java.
  • Systématiser le traitement des exceptions.
  • Garantir une gestion cohérente des erreurs dans l'application.
  • Savoir quand créer une nouvelle exception

Terminologie

Envoyer une exception Consiste à envoyer une exception avec un throw
Traiter une exception Consiste à intercepter une exception avec un catch
Exception implicite

Exception étendant RuntimeException, et n'étant pas déclarée dans la signature de la méthode qui l'envoi

Dans cet exemple, NotFoundException est une exception implicite car elle sous classe RuntimeException.


public class UserService {
  private Map _users;

  public User searchUser(String userId) { 
    User user = (User)_users.get(userId);
    if( user == null ) 
      throw new NotFoundException("User " + userId); 
    return user; 
  } 
}

public class NotFoundException extends RuntimeException { 
  NotFoundException(String quoi) { 
    super(quoi + ": Not found"); 
  } 
} 
Exception explicite

Exception n'étendant pas RuntimeException, à déclarer dans la signature des méthodes qui l'envoi.

Dans cet exemple, SoldeInsuffisantException est une exception explicite car elle ne sous classe pas RuntimeException.


public class CompteBancaire {
  private float _solde;

  public void debit(float montant) throws SoldeInsuffisant {
    if( _solde < montant )
      throw new SoldeInsuffisant("debit de " + montant + "impossible");
    _solde -= montant;
  } 
} 

public class SoldeInsuffisantException extends Exception { 
  SoldeinsuffisantException(String msg) { 
    super(msg); 
  } 
} 
Les Exceptions applicatives Ces exceptions sont créées par l'application et ont une signification métier ou applicative, par exemple l'exception SoldeInsuffisantException est une exception applicative.
Les Exceptions explicites des API Java Exception explicites retournées par l'utilisation d'une API Java tel que java.sql ou java.io qui peuvent envoyer respectivement SQLException ou IOException.
Les Exception techniques de la JVM

Ces exceptions proviennent d'erreur de programmation, par exemple NullPointerException ou IndexOutOfBoundsException.

Ces exceptions peuvent se produire à tout moment dans le code Java.

Conception

ImplicitException (abstract) Classe de base des exceptions implicites supportant les exceptions imbriquées.
ExplicitException (abstract) Classe de base des exceptions explicites supportant les exceptions imbriquées.
TechnicalException Exception signalant qu'une erreur technique s'est produite. Permet de renvoyer les exceptions explicites des API Java.
InvalidFormatException Signal un format incorrect
ParameterException Signal une valeur incorrecte pour le paramètre d'appel d'une méthode
MandatoryParameterException Une référence passée en paramètre d'appel à une méthode vaut null.
OutOfRangeParameterException La valeur d'un paramètre d'appel n'est pas correcte.
ObjectStateException L'objet n'est pas dans un état permettant le déclenchement d'une méthode.
MoreThanOneException Signal q'une méthode de recherche d'une valeur a récupérée plus d'une valeur.
NotFoundException Signal qu'aucune valeur n'a été trouvé par une méthode de recherche

Règles de conception

Utiliser les classes de base fournies

Ne jamais étendre directement ni Exception ni RuntimeException. Utiliser les classes de base ExplicitException et ImplicitException.

Ajouter des exceptions générales

Les exceptions d'intéret général doivent être placées dans un package partagé avec le reste de l'application.

Choisir entre exception explicite et explicite

Les exceptions applicatives doivent être explicites.
Les exceptions techniques doivent être implicites.

Enrober les exceptions techniques explicites des API Java dans une exception implicite

Certaines exceptions techniques envoyées par des API java sont explicites: par exemple, SQLException, IOException ou RemoteException.

Ces exceptions doivent être traitées dans la méthode et renvoyées dans une exception explicite de l'application ou dans une exception implicite telle que TechnicalException.

TechnicalException.rethrow est une méthode utilitaire qui lève une TechicalException en conservant une référence sur l'exception d'origine (exceptions imbriquées), par exemple:


public int loadCounter(String filename) {
  FileReader reader = null;
  int counter;

  try {
   reader = new FileReader(filename);
   ...
  } catch(FileNotFoundException e) {
    // Renvoyer l'exception dans une exception implicite
    throw TechnicalException.rethrow("Cannot open counter file " + filename, e); 
  } finally {
    if( reader != null ) reader.close();
  }
  return counter;
}

Pas de bloc catch vide

Les blocs catch doivent:

  • Renvoyer l'exception
  • Traiter l'exception et continuer le traitement.

Les blocs catch vide sont interdits ou se contentant d'ajouter un message dans un log, sauf cas particuliers.

Interdit !

public int loadCounter(String filename) {
  FileReader reader = null;
  try {
    reader = new FileReader(filename);
  } catch(Exception e) {}
}

Maintenir l'intégrité dans le bloc finally

Toute ressource devant être explicitement libérée doit l'être dans le bloc finally, par exemple, un stream, ou une connexion JDBC .

Cette remarque s'applique même si aucune exception explicite n'est envoyée dans le code de la méthode: ne pas oublier que toute ligne de code java peut potentiellement envoyer une exception.

Interdit !

public int loadCounter(String filename) throws FileNotFoundException {
  FileReader reader = new FileReader(filename);
  ...
  reader.close();
}
		

Ce code devrait ressembler à:

public int loadCounter(String filename) throws FileNotFoundException {
  FileReader reader = null;
  try {
    reader = new FileReader(filename);
    ...
  } finally {
    if( reader != null ) reader.close();
  }
}
		

Ne pas retourner de code erreur

Les méthodes ne doivent jamais retourner une valeur spéciale pour signaler une erreur, par exemple:

Interdit !

public int loadCounter(String filename) {
  FileReader reader = null;
  int counter;
  try {
    reader = new FileReader(filename);
    ...
    return counter;
  } finally {
    if( reader != null ) reader.close();
      return -1; 
  }
}

Cette méthode doit utiliser une exception:

public int loadCounter(String filename) {
  FileReader reader = null;
  int counter;
  try {
    reader = new FileReader(filename);
    ...
    return counter;
  } catch(FileNotFoundException e) {
    throw new NotFoudnException("File " + filename", e);
  } finally {
    if( reader != null ) reader.close();
  }
}

Laisser les exceptions remonter jusqu'à l'interface utilisateur

Toutes les exceptions techniques doivent interrompre le traitement de la requête utilisateur et provoquer l'affichage d'une page d'erreur.

Le code des méthodes de l'application traitant les requêtes utilisateur, comme les actions Struts, doivent toujours se trouver dans un bloc try / catch. Le bloc catch doit provoquer l'affichage d'une page d'erreur et tracer l'exception dans les logs de l'application.

public ActionForward executeImpl( ActionMapping mapping, ActionForm form,
                                  HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException, SQLException, AppException {
  try {
    // Code de traitement de la requête
    return mapping.forward("success");
  } catch(Exception e) {
    log.error("Action login failed", e);
    return mapping.forward("exception");
  }
}
Vous pouvez aussi utiliser le bloc <exception> dans le fichier de configuration struts.

(c) Business Technology Consulting 2005-2007