Programmation Orientée Objet Introduction à Java
Transcription
Programmation Orientée Objet Introduction à Java
Programmation Orientée Objet Exceptions et assertions Julien Provillard http://www.i3s.unice.fr/~provilla/poo/ [email protected] Programmation orientée objet Objectifs Robustesse et Exceptions Error, RuntimeException Exceptions (non) contrôlées try catch, finally, ressources Correction et Assertions Mot clé assert 2 Programmation orientée objet Fiabilité d’un programme Correction Donne un résultat correct lorsqu’il fonctionne en mode "normal" Les assertions permettent de vérifier qu’on est dans un mode "normal" Robustesse Fonctionne même lorsque l’environnement ne respecte pas le contrat (données erronées, état inconsistant) Les exceptions permettent de gérer des anomalies lors de l’exécution et de rétablir un environnement stable ou de sortir proprement du programme. 3 EXCEPTIONS Représentent des évènements anormaux du système 4 Programmation orientée objet Les exceptions sont des objets La classe Exception représente des évènements anormaux (qui ne doivent pas se produire lors d’une exécution normale). Il faut décrire le fonctionnement normal du programme dans un bloc try Prévoir (éventuellement) des situations anormales dans un/des bloc(s) catch Réagir à ces situations anormales pour pallier aux erreurs éventuelles (normalement exceptionnelles/rares) de l’environnement On peut lever/lancer les exceptions (instances) throw uneException; Permet de séparer la détection d’une anomalie de son traitement Provoque une rupture du flot d’exécution 5 Programmation orientée objet NumberFormatException: try/catch On peut attraper les exceptions pour détecter une erreur class Somme { static public void main(String[] args) { int somme = 0; catch: for(String arg : args) { try: Fonctionnement normal Fonctionnement exceptionnel en cas d’erreur try { somme += Integer.parseInt(arg); } catch (NumberFormatException e) { System.err.println(arg + " n’est pas un nombre!"); } } Test : System.out.println("Somme = " + somme); java Somme 12 pasUnNombre 14 } pasUnNombre n’est pas un nombre! } Somme = 26 6 Programmation orientée objet Synopsis: try catch try { // fonctionnement normal … } catch (XXXException e) { // cas si XXXException se produit } catch (YYYException e) { // cas si YYYException se produit } Attention: On ne peut pas attraper une exception qui ne peut pas être lancée! (erreur de compilation) XXXException peut être une sous-classe de YYYException YYYException ne peut pas être une sous-classe de XXXException Les exceptions levées en dehors de try (avant, dans le catch, après) ne sont pas attrapées 7 Programmation orientée objet Traitement des exceptions Une méthode peut décider D’attraper les exceptions lancées et les traiter De propager les exceptions • Il faut le déclarer dans la signature de la méthode selon la nature • Ex: FileReader(String pathname) throws FileNotFoundException D’attraper et les relancer ou d’en lancer d’autres (à déclarer) Propagation C’est la méthode appelante qui la récupère La méthode main peut aussi propager des exceptions 8 Programmation orientée objet Traitement des exceptions Dans un bloc try Le code entre l’instruction qui a levée l’exception et la fin du bloc try n’est pas exécuté Le premier bloc catch compatible est exécuté L’exécution se poursuit normalement après le dernier bloc catch ! 9 Programmation orientée objet Traitement des exceptions Pas d’exception levée : Si aucune exception n’est levée dans le bloc try Alors les blocs catch sont ignorés L’exécution se poursuit normalement après le dernier bloc catch 10 Programmation orientée objet Traitement des exceptions Exception pas attrapée Certaines exceptions ne sont pas obligatoirement attrapées (RuntimeException) Le message porté par l’exception est affiché Le Thread dans lequel l’exception a été lancée meurt • Les autres continuent leur exécution Dans la méthode main La méthode main peut aussi propager les exceptions ! 11 Programmation orientée objet java.lang.Throwable Toutes les exceptions sont de type Throwable Throwable Error Exception RuntimeException XXXException YYYException 12 Programmation orientée objet java.lang.Throwable Toutes les exceptions sont de type Throwable Throwable Erreurs graves JVM Error Exception RuntimeException XXXException YYYException 13 Programmation orientée objet Error Réservées aux erreurs de la JVM OutOfMemoryError NoSuchMethodError Recommandations Ne devraient pas arriver Très rare qu’on les attrape Ne devraient pas être lancées par les utilisateurs Pas de raison de faire des classes filles 14 Programmation orientée objet java.lang.Throwable Toutes les exceptions sont de type Throwable Throwable Error Exceptions noncontrôlées par le compilateur try/catch optionnel Exception RuntimeException XXXException YYYException 15 Programmation orientée objet RuntimeException Usage A priori si l’on pense que le problème ne pourra pas être résolu (dans un catch) Pour ne pas forcer à alourdir le code Quelques RuntimeException NullPointerException ArrayIndexOutOfBoundsException NumberFormatException ClassCastException 16 Programmation orientée objet java.lang.Throwable Toutes les exceptions sont de type Throwable Throwable Exceptions contrôlées => try/catch obligatoire Error Exception RuntimeException XXXException YYYException 17 Programmation orientée objet Exceptions contrôlées Définition Doivent être • Soit attrapées (try/catch) • Soit propagées (throws dans la signature) Contaminant vers la méthode appelante Attention Peut avoir un throws sans lancer l’exception Peut propager plusieurs exceptions dans un throws Ne peut pas avoir un catch si l’exception ne peut pas être lancée Quelques exceptions contrôlées ClassNotFoundException IOException (toutes celles de java.io) • EOFException • FileNotFoundException InterruptedException 18 Programmation orientée objet Lancer une exception L’utilisateur peut lancer des exceptions Soit en utilisant les classes prédéfinies Soit en définissant de nouvelles classes qui héritent de RuntimeException ou de Exception Peut avoir à instancier un nouvel objet Exemple: class Validate { public static void notNull(Object obj) { if (obj == null) throw new NullPointerException("The object must not be null"); } } 19 Programmation orientée objet Exemple: CompteBancaire Le crédit d’un montant négatif n’est pas prévu class CompteBancaire { int solde = 0; void crediter(int somme) { if (somme < 0) throw new IllegalArgumentException("somme négative illégale!"); solde += somme; } } Note: IllegalArgumentException est une RuntimeException 20 Programmation orientée objet Définir ses propres exceptions Exception non-contrôlée class DecouvertException extends RuntimeException { CompteBancaire compte; DecouvertException(CompteBancaire c) { super("Découvert non autorisé sur " + c); this.compte = c; } } Usage class CompteBancaire { int solde = 0; void debiter(int somme) { if (somme > solde) throw new DécouvertException(this); solde -= somme; } } 21 Programmation orientée objet Exceptions et redéfinition Quand on redéfinit une méthode, on ne peut pas déclarer plus d’exceptions contrôlées que la méthode redéfinie Il faut renvoyer : les mêmes exceptions Ou des sous-classes de ces exceptions Ou moins d’exceptions (éventuellement aucune) 22 Programmation orientée objet Exceptions dans les constructeurs Si une exception est levée dans un constructeur Et qu’elle n’est pas attrapée par le constructeur Alors aucune instance n’est créée 23 Programmation orientée objet Définir ses propres exceptions Exception contrôlée class DecouvertException extends Exception { CompteBancaire compte; DecouvertException(CompteBancaire c) { super("Découvert non autorisé sur " + c); this.compte = c; } } Usage class CompteBancaire { int solde = 0; void debiter(int somme) throws DecouvertException { if (somme > solde) throw new DecouvertException(this); solde -= somme; } } 24 Programmation orientée objet Exceptions vs tests Exemple : Tentative d’ouverture d’un fichier public static FileReader openFile(String path) { try { return new FileReader(path); } catch (FileNotFoundException ex) { return null; // cas réellement exceptionnel? } } On gère une exception que l’on aurait pu prévoir. Le chemin existe-t-il? Désigne-t-il un fichier? Celui-ci est-il accessible? Attraper une exception a un coût élevé, il ne faut pas se baser sur les exceptions pour gérer des cas prévisibles. 25 Programmation orientée objet Exceptions vs tests Exemple : Tentative d’ouverture d’un fichier public static FileReader openFile(String path) { File file = new File(path); FileReader reader = null; if (file.exists() && file.isFile() && file.canRead()) { try { reader = new FileReader(file); } catch (FileNotFoundException ex) { } // Vraiment un cas exceptionnel! } return reader; } 26 LES ASSERTIONS Pré et post-conditions 27 Programmation orientée objet Mot clé assert Depuis le JDK 1.4 assert boolean_expression; assert boolean_expression : "message d’erreur"; Permet de s’assurer qu’une propriété est vraie Si l’expression booléenne est vraie, rien ne se passe Sinon, une AssertionError est lancée Usage Pré-condition: au début d’une méthode Post-condition: à la fin d’une méthode Invariant: au milieu d’un code compliqué (boucle) 28 Programmation orientée objet Exemple: CompteBancaire Le crédit d’un montant négatif n’est pas prévu class CompteBancaire { int solde = 0; void crediter(int somme) { assert somme >= 0 : "somme négative illégale :" + somme; solde += somme; } } Note: En général, ce sera garanti par l’environnement d’appel (interface graphique, application principale, …) 29 Programmation orientée objet Activation Activation Lors de l’exécution • Si on n’active pas (comportement pas défaut), alors le code est ignoré • Si on active, cela peut produire des exceptions Test vs. Production Pendant les tests, les assertions sont activées En production, les assertions sont normalement désactivées 30 Programmation orientée objet Activation Pour activer les assertions java –ea Pour activer pour un paquetage ou une classe java –ea:<nom-paquetage>... java –ea:<nom-classe> Pour désactiver pour un paquetage ou une classe java –ea –da:<nom-paquetage>... java –ea –da:<nom-classe> 31 Programmation orientée objet Assertions ou exceptions? Les exceptions doivent être utilisées Pour vérifier la correction des paramètres des méthodes publiques Lorsqu’une situation exceptionnelle se produit Pour gérer ces situations exceptionnelles Les assertions doivent être utilisées Pour les pré et post-conditions et les invariants de boucles des méthodes privées (sauf si une exception doit être remontée à la méthode appelante) Pour vérifier qu’une propriété attendue est vraie De manière générale, les exceptions assurent la robustesse du code tandis que les assertions vérifient sa correction (une AssertionError devrait indiquer une erreur de programmation) 32 Programmation orientée objet Assertions ou exceptions? Exception contrôlée class DecouvertException extends Exception { CompteBancaire compte; DecouvertException(CompteBancaire c) { super("Découvert non autorisé sur " + c); this.compte = c; } Assertion : l’environnement } Usage d’appel est sensé vérifier que toutes les sommes manipulées sont positives class CompteBancaire { int solde = 0; void debiter(int somme) throws DecouvertException { assert somme >= 0 : "somme négative illégale :" + somme; if (somme > solde) throw new DécouvertException(this); solde -= somme; } Exception : l’appel de méthode } est valide mais entraîne une situation exceptionnelle 33 COMPLÉMENTS SUR LES EXCEPTIONS 34 Programmation orientée objet Multi-catch (JDK 7.0) try { // fonctionnement normal } catch (XXXException e) { // cas si XXXException se produit } catch (YYYException e) { // cas si YYYException se produit } Que faire si les deux blocs sont identiques pour éviter la duplication du code? Solution n°1 : Attraper un ancêtre commun de XXXException et YYYException try { // fonctionnement normal } catch (Exception e) { /* cas si XXXException ou * YYYException se produit */ } Mauvaise pratique, on attrape désormais toutes les exceptions! 35 Programmation orientée objet Multi-catch (JDK 7.0) try { // fonctionnement normal } catch (XXXException e) { // cas si XXXException se produit } catch (YYYException e) { // cas si YYYException se produit } Que faire si les deux blocs sont identiques pour éviter la duplication du code? Solution n°2 : Factoriser dans une méthode try { // fonctionnement normal } catch (XXXException e) { someMethod(...); } catch (YYYException e) { someMethod(...); } Fastidieux, il peut être nécessaire de passer beaucoup d’informations à la méthode. 36 Programmation orientée objet Multi-catch (JDK 7.0) try { // fonctionnement normal } catch (XXXException | YYYException e) { // cas si XXXException ou YYYException se produit } Attention: e est final XXXException : pas un sous-type de YYYException YYYException : pas un sous-type de XXXException 37 Programmation orientée objet Propager les exceptions Il ne faut pas attraper les exceptions trop vite Choisir le niveau le mieux adapté pour retrouver un état « normal » On attrape que si l’on est sûr de ne pas avoir un état dégradé après Il est possible d’attraper une exception pour rétablir partiellement l’état du système avant de la relancer au niveau supérieure. Au plus près de la cause de l’exception Les blocs try et catch sont des blocs d’instructions Les variables déclarées dans ces blocs meurent à la fin du bloc try et catch sont deux blocs séparés ! • Le bloc catch ne connaît pas les variables déclarées dans le bloc try 38 Programmation orientée objet Throwable.printStackTrace() La méthode printStackTrace Affiche l’état de la pile au moment de l’exception C’est-à-dire la liste des méthodes qui ont conduit à l’exception (avec le numéro de ligne) Voir aussi Throwable.printStackTrace(PrintWriter) java.io.FileNotFoundException: ..\reference.txt.cs (Le fichier spécifié est introuvable) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(Unknown Source) at java.util.Scanner.<init>(Unknown Source) at fr.unice.cesar.BarChart.init(BarChart.java:36) at sun.applet.AppletPanel.run(Unknown Source) at java.lang.Thread.run(Unknown Source) printStackTrace peut exposer des informations sensibles! 39 Programmation orientée objet Synopsis: try[-catch]-finally try { // fonctionnement normal } catch (XXXException e) { // cas si XXXException se produit } finally { // le mot de la fin (dans tous les cas) } Bloc finally: Exécuté dans tous les cas • qu’il y ait eu ou non une exception • Même s’il y avait un return dans le try et/ou catch finally est exécuté • Après le try, après le catch • Avant de passer la main à la méthode appelante 40 Programmation orientée objet finally vs. try/catch finally est prioritaire sur ce qui se passe dans try et catch Si une exception est levée dans finally alors le return du try et du catch ne se produisent pas Si finally contient un return alors les exceptions propagées dans le try ou catch ne sont pas lancées Si finally ne fait ni return ni throw alors l’exception ou la valeur renvoyée dans le try/catch sont prises en compte ! Convention: Il faut éviter cette situation 41