Cours Java : deuxième saison

publicité
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 1
Cours Java : deuxième saison
➢
Cours 7 : Exceptions, tests unitaires et assertions
➢
Cours 8 : Design Patterns 1
➢
Cours 9 : Design Patterns 2
➢
Cours 10 : Interfaces graphiques en Swing
➢
Cours 11 : Collections
Contact: [email protected]
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 2
Exceptions, Tests Unitaires et Assertions
●
Introduction aux exceptions
●
Traitement des exceptions en Java
●
Conception par contrat
●
●
–
Prérequis
–
Garanties
Tests unitaires avec Junit
–
Classes de test
–
Méthodes de tests
Erreurs logiques et assertions
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 3
Programmes robustes
●
Approches formelles : ex. Floyd/Hoare
–
●
Approches semi­formelles : ex. Contrat
–
●
Assez Fiable, Moins long et coûteux
Approches empiriques : ex. Junit
–
●
Fiable, Long, Coûteux
Moins fiable, moins long et coûteux Important: approches complémentaires
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 4
Dans ce cours
●
Gestion propre des erreurs en Java
–
●
●
Important: souvent mal fait
Conception par contrat « light »
–
Méthode de conception
–
Systématise la gestion des exceptions
Test unitaire avec Junit
–
Pour écrire proprement des tests
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 5
Typologie des erreurs
●
Erreurs de compilation : par le compilateur javac
–
●
Erreurs de syntaxe, pbm. de typage
Erreurs d'exécution : par la machine virtuelle java
–
Erreurs système : générée par l'environnement => RuntimeException
–
Erreurs contractuelles : mauvaise utilisation d'un objet => Exception
–
Erreurs logiques : un bug du programme ! => AssertionError
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 6
Les Exceptions
●
En Java, toute erreur est une exception
●
Une exception = un objet d'une classe qui
●
–
hérite de java.lang.RuntimeException : exceptions système, non­vérifiées par le compilateur (pas de déclarations throws)
–
hérite de java.lang.Exception : exceptions vérifiées par le compilateur (nécessité des déclarations throws)
Règle : on ne définit nous ­même que des exception non­vérifiées, donc on héritera systématiquement de java.lang.Exception (ou d'une sous­classe)
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 7
Pourquoi les exceptions ?
●
Erreurs à la construction
–
●
Un constructeur ne retourne rien, donc surement pas un code d'erreur
Séparation des préoccupations
–
D'un côté : code qui génère les erreurs => throw
–
De l'autre côté : code qui traite les erreurs => try ...
catch
●
Syndrome du « segmentation fault »
–
Messages d'erreurs
–
« remontée » de la pile d'exécution
–
Possibilité de récupération (poursuivre malgré l'exception)
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 8
Traitement des exceptions
●
Traitement immédiat
–
●
Clauses multiples
–
●
Plusieurs types d'exceptions traitées au même endroit
Délégation / Filtrage
–
●
On traite l'exception dès qu'on la détecte, c'est le cas le plus fréquent
On délègue le traitement de l'exception, même si on la détecte
Clause finale
–
Du code exécuté quoi qu'il arrive (exception levée ou non)
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 9
Traitement immédiat
Les blocs try ... catch :
Public class MaClasse {
....
public void maMethode(...) {
try {
// ici, code générant éventuellement
// une exception de type MonException
} catch(MonException e) {
// traitement de l'exception
}
....
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 10
Exemple: utilisation du JDK (1/2)
Dans la doc. du jdk:
FileReader
public FileReader(String fileName)
throws FileNotFoundException
Creates a new FileReader, given the name of the file to read from.
Parameters:
fileName - the name of the file to read from
Throws:
FileNotFoundException - if the named file does not exist, is a
directory rather than a regular file, or for some other reason
cannot be opened for reading.
Important: si on veut utiliser une méthode qui throws une exception, le programme ne compilera pas si on indique comment traiter cette exception
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 11
Exemple: utilisation du JDK (2/2)
Mode d'emploi:
Public class MaClasse {
....
public void maMethode(...) {
try {
// ici, code générant éventuellement
// une exception
FileReader fr = new FileReader("toto.txt");
// et la suite ...
} catch(FileNotFoundException e) {
// traitement de l'exception
System.err.println("Je ne trouve pas toto.txt");
}
....
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 12
Clauses multiples : pourquoi ?
●
Problèmes
–
Un même instruction peut générer plusieurs types d'exception différents
Exemple: constructeur de java.io.FileInputStream
throws FileNotFoundException et SecurityException
On veut mettre plusieurs instructions dans le corps d'un try ... catch, chaque instruction peut lever plusieurs types d'instructions
●
–
●
Exemple: –
première instruction : constructeur FileReader peut lever FileNotFoundException
–
Second instruction: lecture dans le fichier avec méthode read de FileReader, peut lever IOException
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 13
Clauses multiples : comment ?
Public class MaClasse {
....
public void maMethode(...) {
try {
// ici, code générant éventuellement
// une exception
FileReader fr = new FileReader("toto.txt");
int carac = fr.read();
// et la suite ...
} catch(FileNotFoundException e) {
// traitement de l'exception
System.err.println("Je ne trouve pas toto.txt");
} catch(IOException e) {
// traitement de l'exception
System.err.println("Problème de lecture");
}
....
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 14
Clauses multiples et héritage
●
●
Les exceptions sont des objets, ils sont donc instances de classes et on peut donc hériter de classes d'exceptions
L'ordre dans lequel on liste les exceptions « catch » est important
–
D'abord les sous­classes d'exceptions les moins génériques
–
Ensuite les super­classes d'exceptions les plus génériques
Raison: c'est simple, si on traite d'abord un cas plus générique, on ne traitera jamais le cas le plus spécifique
●
Ne pas s'inquiéter, le compilateur vérifie tout cela
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 15
Que faire dans une clause catch ?
●
Au minimum (phase de développement):
–
Afficher un message d'erreur
●
●
●
Conseil : } catch(MonException e) {
System.err.println("Erreur : patati");
e.printStackTrace(System.err);
}
Au mieux (programme diffusé):
–
Récupération de l'erreur
–
Délégation ou filtrage : prévenir les « supérieurs »
INTERDIT !
} catch(MonException e) {
// ici je ne fais rien
}
–
De ne rien faire
–
Pourquoi ? Parce que l'utilisateur ne sait pas qu'il s'est passé quelque chose !
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 16
Délégation
Question: que faire si on ne veut/peut pas traiter une exception ?
Réponse 1: on peut déléguer à celui qui nous a appelé
public class MaClasse {
....
public void maMethode(...) throws FileNotFoundException,
IOException {
// ici, code générant éventuellement
// des exceptions
FileReader fr = new FileReader("toto.txt");
int carac = fr.read();
// et la suite ...
...
}
}
Remarque: si on oublie le throws alors le compilateur se plaint
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 17
Filtrage
Question: que faire si on ne veut/peut pas traiter une exception ?
Réponse 2: on peut filtrer pour celui qui nous a appelé
public class MaClasse {
....
public void maMethode(...) throws FichierException {
try {
FileReader fr = new FileReader("toto.txt");
int carac = fr.read();
// et la suite ...
} catch(Exception e) { // pour toute exception
FichierException fe = new FichierException("problème de fichier");
fr.initCause(e); // enregistrer la cause
throw fr; // lancer l'exception filtrée
}
}
}
Remarque: la classe FichierException est une exception
personalisée (cf. suite du cours)
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 18
Clause finale
Du code exécuté dans tous les cas, même si exception il y a
public class MaClasse {
....
public void maMethode(...) {
try {
// ici, code générant éventuellement
// une exception
FileReader fr = new FileReader("toto.txt");
// et la suite ...
} catch(FileNotFoundException e) {
// traitement de l'exception
System.err.println("Je ne trouve pas toto.txt");
} finally {
fr.close(); // en fait pas nécessaire en Java
}
...
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 19
Exceptions et conception par contrat
●
●
●
Questions rituelles sur les « exceptions »
–
Pourquoi créer ses propres classes d'exceptions ?
–
Quand et pourquoi signaler une exception personnalisée ?
Réponses de la conception par contrat:
–
On créer une classe d'exception (ou hiérarchie) par catégorie de contrat (en général une hiérarchie par paquetage de 10 à 20 classes maxi)
–
On signale une exception si un contrat est rompu
La conception par contrat fournit de plus:
–
un moyen de gérer les erreurs logiques avec les assertions
–
Enfin, elle sert de guide pour l'élaboration des tests unitaires
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 20
Principes de la conception par contrat
●
Fournisseurs
–
●
Clients
–
●
Classes/Méthodes que l'on définit nous­même
Code externe (que l'on ne voit pas) et qui utilise nos classes fournisseurs
Contrats (pour chaque méthode publique d'une classe en cours de conception) :
–
Prérequis (ou précondition externe) : ce que les clients doivent respecter lorsqu'ils font appel au fournisseur en cours de conception.
–
Garanties (ou postcondition externe) : ce que le fournisseur se charge de fournir si le client respecte sa part du contrat et que tout se passe bien.
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 21
Exemple de contrat (monde réel)
●
Fournisseur:
–
●
Clients:
–
●
Société de chemins de fer
Passagers
Contrat : transport de Paris à Marseille
–
Prérequis (conditions booléennes imposées au client) :
●
●
–
Le client paye son billet
Le client arrive à l'heure pour son train
Garanties (conditions booléennes vraies après traitement):
●
●
Transport en tout sécurité du passager dans les délais prévus
Prévoir une indeminisation en cas de retard
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 22
Exemple (monde des objets) 1/7
Une classe de Cube bornée contenant du liquide (en litres)
public class CuveBornee {
private double niveau;
private double limite;
public CuveBornee(double limite) {
this.limite = limite; niveau = 0;
}
public double getNiveau() { return niveau; }
public void remplir(double quantite) {
...
}
public void vider(double quantite) {
...
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 23
Exemple (monde des objets) 2/7
●
Fournisseur:
–
●
Clients:
–
●
Méthode remplir() de la classe CuveBornee
Toute expression qui invoque la méthode remplir sur un objet de la classe CuveBornee depuis l'extérieur (ex.: dans une classe de test pour cuve bornée, dans un programme qui a besoin d'une cuve bornée, etc.)
Contrat: remplir la cuve avec du liquide
–
Prérequis : le liquide versé par le client, ajouté au niveau actuel ne dépasse pas la limite
–
Garanties : le niveau est l'ancien niveau auquel on ajoute la quantité versée par le client
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 24
Exemple (monde des objets) 3/7
Que peut­il se passer ?
●
Le client assure les prérequis
–
Le fournisseur fournit les garanties
–
Le client peut tester les garanties => Ecrire un test
● Si un test de garantie échoue, alors il s'agit d'un bug !
Un problème d'environnement survient (ex. plus de mémoire) : alors une exception système est levée par Java (nous, on ne s'en occupe pas à priori)
●
●
Le client n'assure pas les prérequis
–
Le fournisseur lève une exception personnalisée
=> définir une (ou plusieurs) classe(s) personnalisée(s)
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 25
Exemple (monde des objets) 4/7
Phase 1 : Classe(s) d'exception(s) personnalisée(s)
// Exception de base pour tous les problèmes de cuve
public class CuveException extends Exception {
public CuveException(String message) {
super("Problème de cuve : " + message);
}
}
// Exception spécifique pour le contrat de remplir()
public class CuvePleineException extends CuveException {
public CuvePleineException() {
super("Cuve pleine");
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 26
Exemple (monde des objets) 5/7
Phase 2 : Vérification des prérequis
=> tester la condition de prérequis
=> lever une exception personnalisée si la condition est fausse
Public class CuveBornee {
...
public void remplir(double liquide) throws CuvePleineException {
// PREREQUIS : Le liquide versé, ajouté au niveau actuelle,
//
ne dépasse pas la limite
if(niveau+liquide>limite)
throw new CuvePleineException();
// ... la suite
}
...
}
Rappels : Le fournisseur est la méthode remplir, Les clients sont ceux qui invoquent la méthode
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 27
Exemple (monde des objets) 6/7
Phase 3 : Description des traitements
=> (enfin) le code java de la méthode !
Public class CuveBornee {
...
public void remplir(double liquide) throws CuvePleineException {
// PREREQUIS : Le liquide versé, ajouté au niveau actuelle,
//
ne dépasse pas la limite
if(niveau+liquide>limite)
throw new CuvePleineException();
// TRAITEMENT
niveau = niveau+liquide;
// la suite
}
...
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 28
Exemple (monde des objets) 7/7
Phase 4 : Expression des garanties
=> un commentaire qui permettra ensuite de créer un test
public class CuveBornee {
...
public void remplir(double liquide) throws CuvePleineException {
// PREREQUIS : Le liquide versé, ajouté au niveau actuelle,
//
ne dépasse pas la limite
if(niveau+liquide>limite)
throw new CuvePleineException();
// TRAITEMENT
niveau = niveau+liquide;
// GARANTIE : le niveau est l'ancien niveau auquel on ajoute
//
la quantité versée par le client
// this.getNiveau() = old.getNiveau()+liquide;
// Problème : java ne connait pas old, donc commentaire !
}
...
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 29
Test unitaire avec Junit
●
Evidence : il faut tester ses programmes
●
Constat : manque de méthodologie
●
–
Faire un main dans une classe séparée
–
tester « un peu au pif »
Solution : Junit (sur http://www.junit.org)
–
Pour chaque classe MaClasse, créer une classe MaClasseTest qui hérite de junit.framework.TestCase
–
Pour chaque méthode maMethode() de MaClasse (modulo surcharge), créer (au moins) une méthode de test testMaMethode() dans MaClasseTest
–
Il faut aussi créer des test unitaires pour tester la combinaison de plusieurs méthodes
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 30
Structure d'une classe de test
import junit.framework.*;
public class MaClasseTest extends TestCase {
private MaClasse mon_objet; // pour tout les tests
public MaClasseTest() {
mon_objet = null;
}
public void setUp() { // préparation global de tous les tests
mon_objet = new MaClasse(...);
}
public void setDown() { // terminaison de tous les tests
mon_objet = null;
}
public void testMaMethode() { // test unitaire
// ici les tests pour maMethode() dans MaClasse
// on peut utiliser mon_objet ou utiliser des
// objets MaClasse locaux
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 31
Contenu d'un test unitaire
Chaque test contient:
●
Du code java réalisant les tests
●
Des assertions de tests vérifiant les résultats/modifications
assertTrue(<expression booléenne>) => vrai ok, faux erreur de test
Remarque: assertTrue(true) toujours vrai et assertTrue(false) toujours faux
●
import junit.framework.*;
public class MaClasseTest extends TestCase {
...
public void testMaMethode() { // test unitaire
// ici les tests pour maMethode() dans MaClasse
// on peut utiliser mon_objet ou utiliser des
// objets MaClasse locaux
<resultat> = mon_objet.MaMethode(...);
assertTrue(<test booléen sur le résultat>);
// ... autres tests possibles
}
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 32
Exemple : Test de la cuve bornée
1) Tester les prérequis
public class CuveBorneeTest extends TestCase {
private CuveBornee cuve1;
...
public void setUp() { cuve1 = new CuveBornee(10.0); }
...
public void testRemplir() {
// 1) Tester le prérequis
// 1.a) prérequis non valide
try { cuve1.remplir(12.0);
assertTrue(false); // il ne faut pas arriver ici
} catch(CuvePleineException e) {
assertTrue(true); // il faut arriver ici
}
// 1.b) prérequis valide
try { cuve1.remplir(4.0);
assertTrue(true); // il faut arriver ici
} catch(CuvePleineException e) {
assertTrue(false); // il ne faut pas arriver ici
}
}
...
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 33
Exemple : Test de la cuve bornée
2) Tester les garanties
public class CuveBorneeTest extends TestCase {
...
public void testRemplir() {
// 1) Tester le prérequis
...
double old_niveau = cuve1.getNiveau(); // avant de remplir
try { cuve1.remplir(4.0);
assertTrue(true); // il faut arriver ici
} catch(CuvePleineException e) {
assertTrue(false); // il ne faut pas arriver ici
}
// 2) Tester les garanties
// GARANTIE: this.getNiveau() = old.getNiveau()+liquide
assertTrue(cuve1.getNiveau()=old_niveau+4.0);
}
...
}
Remarque : on pourrait aussi cloner la cuve avant de la modifier
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 34
Exemple : Test de la cuve bornée
3) Lancer les tests
java junit.swingui.TestRunner CuveBorneeTest
Attention : il faut que junit.jar et CuveBorneeTest soient dans le CLASSPATH
Remarque: en TME, nous
utiliserons BlueJ, un ide qui intègre junit
cf. http://www.bluej.org
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 35
Erreurs logiques
●
●
Dans la conception par contrat, on a vu comment:
–
Décrire au sein du fournisseur la vérification que les clients respectent leurs prérequis
–
Décrire dans un test unitaire la vérification que le fournisseur fournit ses garanties du point de vue du client
–
Cela nous aide à écrire proprement les intéractions entre clients et fournisseurs mais cela ne nous aide pas à tester la logique interne du fournisseur
Les erreurs logiques sont des bugs
–
Même en étant très rigoureux (par exemple en adoptant la conception par contrat) et en écrivant beaucoup de tests unitaires, il est très difficile de s'assurer que le code d'une méthode fait bien son travail : point de vue du fournisseur
=> on veut aussi tester dans le code du fournisseur
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 36
Les assertions
●
Java fournit un mécanisme : les assertions
–
●
assert(<condition booléenne>)
●
Si vrai : le programme se poursuit normalement
●
Si faux : une exception AssertionError est levée
Attention 1: ne pas confondre
–
assertTrue() est une assertion de test pour les tests unitaires, c'est un mécanisme spécifique de junit
–
assert() est une assertion logique pour le code du fournisseur, c'est un mécanisme standard de Java (> 1.4)
●
Attention 2 : les assertions logiques ne font pas partie du code fonctionnel, on peut les désactiver avec:
java -da
MaClasseMain
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 37
Exemple : assertions pour la cuve bornée
En général, on sépare:
●
Préconditions : assertions avant un traitement
●
Postconditions : assertions après un traitement
public class CuveBornee {
...
public void remplir(double liquide) throws CuvePleineException {
if(niveau+liquide>limite)
throw new CuvePleinException();
// PRECONDITION: le niveau est correct
assert(niveau>=0 && niveau<=limite);
niveau = niveau+liquide;
// POSTCONDITION: le niveau reste correct
assert(niveau>=0 && niveau<=limite);
}
...
}
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 38
Conclusion
●
A partir de maintenant, vous savez:
–
Comment traiter les exceptions:
–
Traitement immédiat
● Délégation ou filtrage
Comment concevoir des classes robustes
●
●
Vision contrat client/fournisseur
–
Votre rôle est de définir le fournisseur
Prérequis et exceptions personnalisées
● Garanties et tests unitaires
Comment ajouter des assertions pour débusquer les bugs
●
–
=> A partir de maintenant, vos programmes Java doivent être robustes
Programmation Objet en Java – Cours 5 Exception – (C) 2005, Frédéric Peschanski 39
Le mot de la fin
●
Exercice à la maison:
–
●
●
Compléter la classe de cuve bornée
Pointeurs:
–
Junit : http://www.junit.org
–
Conception par contrat : http://www.eiffel.com
–
Assertions logiques : http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html
La semaine prochaine:
–
Les design patterns (1/2)
Téléchargement