Exceptions IFT1025: Programmation 2 Jian-Yun Nie Concepts • Erreur vs. Exception – Erreur: Un erreur logique impossible de réparer – Exception: un événement imprévu • Laisser l’exception sans traiter (échec du programme) • Traiter l’exception (le programme continue après le traitement) • Traitement d’exception – Un contrôle de sécurité • • • • Appel d’une méthode dans de bonnes conditions ? Exécution de la méthode se déroule correctement ? … Sinon, quelles alternatives, correction ? – Mécanisme de traitement: général (classe) pour faciliter les traitements Échec d’un programme • Impossibilité pour le système d’accomplir une tâche • 2 raisons d’échec – Erreur logique dans l’implantation (la faute du programmeur) – Impossibilité d’obtenir des ressources nécessaires (e.g. fichier) • Dans le cas d’erreur, pas réparable (seulement un message d’erreur) • Mais pour la second classe: possible de traiter Ressources nécessaires • • • • • • Matériel Système d’exploitation Fichiers Réseau Base de données Utilisateur (interaction) Exception • Apparition d’une situation anormale, détectable, qui conduit à l’échec du programme • Possibilité pour un programme de détecter et traiter certaines exceptions pour éviter l’échec du programme Exemple public class Lecture_mot { static BufferedReader input; public static void main(String[] args) { ouvrir_fichier("liste_mots"); traiter_fichier(); fermer_fichier(); } Si on utilise juste cette ligne, et que "liste_mots" n’existe pas - une exception non traitée, le programme échoue // ouverture du fichier public static void ouvrir_fichier(String nom) { try { input = new BufferedReader( new FileReader(nom)); } catch (IOException e) { System.err.println("Impossible d'ouvrir le fichier d'entree.\n" + e.toString()); System.exit(1); } } // ouvrir_fichier Possibilité de traiter l’exception ici, e.g. demander à l’utilisateur d’entrer un autre fichier Message d’exception … catch (IOException e) { System.err.println("Impossible d'ouvrir le fichier d'entree.\n" + e.toString()); System.exit(1); } Message affiché: Impossible d'ouvrir le fichier d'entree. java.io.FileNotFoundException: liste_mots (No such file or directory) Mécanisme général en Java • Permet de détecter, signaler ou traiter une exception • Non pour traiter des situations prévues • N’est pas un mécanisme de contrôle pour le branchement d’un programme (if, …) – Mais plutôt un autre mécanisme qui contrôle l’exécution Mécanisme général • Exemples d’exemption – Diviser par 0 – Accéder un tableau avec un index invalide Méthode qui appelle: … appel Appel Méthode appelée: … Retour normal Suite normale Normal Traiter l’exception … Exception Message d’exception Mécanisme général • Deux mécanismes en parallèle – Traitement normal – Traitement d’exception (exception handler) • Quand il y a une exception – Le traitement normal s’arrête – Le traitement d’exception prend le contrôle Traitement d’exception en chaîne • méthode_1 appelle méthode_2, qui appelle méthode 3 Méthode_1 Méthode_2 Méthode_3 • Si méthode 3 génère une exception – Message d’exception est envoyé à méthode_2 – Méthode_2 peut • Traiter (attraper) l’exception • Relancer l’exception: le message d’exception sera envoyé à méthode_1 • … • Si une exception n’est traitée par aucune méthode qui appelle: sortie du programme avec un message d’exception Exemple de transmission d’exception Générer une exception • Certaines exceptions standard sont reconnues – ArithmeticException: diviser par 0 – ClassCastException: Casting d’un objet à une mauvaise classe – EOFException: Lire après la fin d’un fichier – IllegalArgumentException: paramètres illégaux ou inappropriés –… • Quand une de ces exceptions est rencontrée, le système lance (throw) un message d’exception Hiérarchie des classes d’exceptions Attraper (catch) une exception • Attraper une exception pour la traiter Bloc où une exception try { statements : : } catch ( ExceptionClass1 object) { statements : : } catch (ExceptionClass2 object) { statements : : }… peut se générer Blocs pour attraper les exceptions Exemple public static void ouvrir_fichier(String nom) { try { input = new BufferedReader( new FileReader(nom)); } catch (IOException e) { System.err.println("Impossible d'ouvrir le fichier d'entree.\n" + e.toString()); System.exit(1); } } Un autre exemple public void getSomeData () throws FileNotFoundException, SecurityException { FileReader in; boolean success = false; //Data file opened int tryNumber = 0; //# of attempts to open datafile int delay = 5 * 1000; //wait in milli secs while (!success) try { tryNumber = tryNumber + 1; in = new FileReader(“DataFile”); success = true; … } catch (SecurityException e) { if (tryNumber == 1) thisThread.sleep(delay); else throw e; } } Exécution avec catch • Si aucune exception est générée (thrown), les instructions dans catch ne sont pas exécutées • Si une exception est générée, l’exception est comparée dans l’ordre avec les clauses de catch (ExceptionClass object) – Si la classe de l’exception match celle de catch: • exécution des instruction de ce catch, • continue après le dernier catch (sauter les autres catches) – Seulement le premier catch compatible avec l’exception est exécuté • Important: Catch d’abord les sous-classes d’exception – Si aucun catch est compatible avec l’exception, • l’exception n’est pas attrapée (non traitée) • transmise à la méthode qui appelle Checked vs. Unchecked • Checked exception – Vérifiée par le compilateur – Si le programme peut générer une telle exception, il doit • Soit la traiter dans le programme • Soit la retransmettre à l’appelant (avec throws dans l’entête) – Typiquement générée à cause de l’environnement – Exemple, IOException – public void getSomeData () throws FileNotFoundException, SecurityException • Unchecked exception – RuntimeException – Problème du programmeur (mauvaise utilisation d’une méthode, d’un objet, …) – Le compilateur ne la vérifie pas – Si un programme peut générer une telle exception, le programme n’a pas à la signaler dans l’entête – public int division(înt a, int b) {return a/b; } Checked vs. Unchecked exception Lancer une checked exception • Signaler au compilateur qu’une méthode peut lancer une exception (non attrapée, non traitée) public void methode() throws ExceptionClass • Exemple public void skip () throws IOException { String s; s = input.readLine(); } • Si une exception apparaît, transmise à l’appelant (caller) Traitement partiel d’exceptions public void getSomeData () throws FileNotFoundException, SecurityException{ FileReader in; try { in = new FileReader (“DataFile”); … } catch (FileNotFoundException e) { //cleanup throw e; // throws it again to its caller } } catch (SecurityException e) { //cleanup throw e; // throws it again to its caller } finally • Exécuter un bloc quel que soit l’exception try { statement ... } finally { statement ... } Exécuter finally même si le bloc try lance ne exception finally • Souvent combiné avec catch try { statement ... } catch (ExceptionClass exceptionObject) { statement ... Même si une exception est } finally { statement ... } attrapée, finally sera toujours exécuté Utile pour s’assurer de certaine sécurité (cleanup) Générer une exception explicitement • Un programme peut aussi générer une exception public class BankAccount throws IllegalArgumentException { public void withdraw(double amount) { if (amount > balance) { IllegalArgumentException exception = new IllegalArgumentException("Amount exceeds balance"); throw exception; } balance = balance - amount; } ... } • Général: throw exceptionObject; • Forcer la méthode qui appelle de traiter cette exception Définir ses propres exceptions • Les classes d’exception prédéfinies ne sont pas suffisamment explicites • On a besoin de faire la différence entre les exceptions pour leurs traitements • Définir une sous-classe d’exception public class NoDataException extends Exception { public NoDataException () { super(); constructeurs } public NoDataException (String s) { super(s); } } • Définir une hiérarchies de classes d’exception Un autre exemple class TemperatureException extends Exception { } class TooColdException extends TemperatureException { } class TooHotException extends TemperatureException { } Classe Exception • Constructeurs Exception() Constructs a new exception with null as its detail message. Exception(String message) Constructs a new exception with the specified detail message. Exception(String message, Throwable cause) Constructs a new exception with the specified detail message and cause. Exception(Throwable cause) Constructs a new exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which typically contains the class and detail message of cause). Classe Throwable • 4 constructeurs • Thrwoable getCause() – Cause de cette exception (ou null) • String getMessage(): – message envoyé par l’exception • String toString() – Générer un message décrivant l’exception • … Penser Exception comme des classes / sous-classes Une TooColdException est aussi une TempretureException, Exception, Throwable Attention aux catches: Catch une sous-classe avant une super-classe Prévenir des erreurs • Certaines erreurs peuvent être détectées ou éviter • Tester la pré-conditon, post-condition ou l’invariant d’une méthode – Pré-condition: condition sous laquelle on l’appelle – Post-condition: condition après la méthode – Invariant: conditions devant être vérifiée tout au long • Test sur pré-condition : facile (assert) • Test sur post-condition et invariant : plus difficile assert • assert booleanExpression ; • assert booleanExpression : expression • Si la condition non satisfaite, AssertionError • Exemple //Interchange list.get(i) and list.get(j) // require 0 <= i, j < list.size() … private <Element> void interchange ( List<Element> list, int i, int j) { assert 0 <= i && i < list.size(): "precondition: illegal i"; assert 0 <= j && j < list.size(): "precondition: illegal j"; … Alternative (public) //Interchange list.get(i) and list.get(j) // require 0 <= i, j < list.size() … public <Element> void interchange ( List<Element> list, int i, int j) { if (0 <= i && i < list.size()) throw new IndexOutOfBoundsException("illegal i“); if (0 <= j && j < list.size()) throw new IndexOutOfBoundsException("illegal j“); … Convention • Méthode utilitaire private: assert • Méthode public: exception – Pourquoi pas d’assert pour tester les paramètres ? • Ce test ne correspondent pas à la spécification de la méthode public • Ne permettrait pas de générer un message d’exception approprié • Activer/Désactiver assertion: – Javac -enableassertions … – Javac -disableassertions … Méthode private ou public • Méthodes public: – Comportement observable de l’extérieur – défini par une spécification • Méthode private – Méthode utilitaire pour faire un traitement interne – N’est pas directement visible de l’extérieur – Non définie par une spécification Exemple • Définir une méthode qui fait retourne le plus petite valeur d’un tableau – Spécification: • Accepter un tableau de nombres entiers • Retourner la plus petite valeur stockée • Cas spécial - tableau vide: un message d’exception – Entête public int plusPetit(int [] a) Implantation • public int plusPetit(int [] a) { Utiliser Exception … return pp(a, 0); } private int pp(int [] a, int ind) { Utiliser Assert … int p = pp(a, ind+1); if (p>a[ind]) return a[ind] else return p; }