Exceptions et assertions

Transcription

Exceptions et assertions
Exceptions, Assertions
Programmation Orientée Objet
Exceptions et assertions
Frédéric Mallet
(sur la base du cours de Richard Grin)
http://deptinfo.unice.fr/~fmallet/
F. Mallet - POO
1
Exceptions, Assertions
Objectifs
Robustesse et Exceptions
Error, RuntimeException,
Exceptions (non) contrôlées
Try-catch, finally, ressources
Correction et Assertions
Mot clé assert
F. Mallet - POO
2
Exceptions, Assertions
Fiabilité: robustesse vs. correction
Correction
Donne les résultats corrects 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)
Les exceptions permettent de détecter des évènements
exceptionnels et maintenir le mode “normal”
F. Mallet - POO
3
Exceptions, Assertions
Représentent des évènements anormaux du système
EXCEPTIONS
F. Mallet - POO
4
Exceptions, Assertions
Les exceptions sont des objets
La classe Exception représente des évènements
anormaux (qui ne doivent pas se produire).
Il faut décrire le fonctionnement normal du programme
• Bloc try
Prévoir (éventuellement) des situations anormales
• Bloc 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 e
F. Mallet - POO
5
Exceptions, Assertions
NumberFormatException: try/catch
On peut attraper les exceptions pour détecter une erreur
class Somme {
static public void main(String[] args) {
try {
int somme = 0;
for(String arg : args)
somme += Integer.parseInt(arg);
try:
Fonctionnement normal
System.out.println(somme);
} catch (NumberFormatException nfe) {
System.err.println(arg+" n’est pas un nombre!");
}
}
}
Test :
catch:
Fonctionnement exceptionnel en cas d’erreur
java Somme 12 pasUnNombre 14
pasUnNombre n’est pas un nombre!
F. Mallet - POO
6
Exceptions, Assertions
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 levé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
F. Mallet - POO
7
Exceptions, Assertions
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: File (String pathname) throws NullPointerException
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 décider aussi de propager
F. Mallet - POO
8
Exceptions, Assertions
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 !
F. Mallet - POO
9
Exceptions, Assertions
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
• Continue/break/return
F. Mallet - POO
10
Exceptions, Assertions
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 !
F. Mallet - POO
11
Exceptions, Assertions
java.lang.Throwable
Toutes les exceptions sont de type Throwable
Throwable
Error
Exception
RuntimeException
XXXException
YYYException
F. Mallet - POO
12
Exceptions, Assertions
java.lang.Error
Toutes les exceptions sont de type Throwable
Throwable
Erreurs graves
JVM
Error
Exception
RuntimeException
XXXException
YYYException
F. Mallet - POO
13
Exceptions, Assertions
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
F. Mallet - POO
14
Exceptions, Assertions
java.lang.RuntimeException
Toutes les exceptions sont de type Throwable
Throwable
Error
Exceptions noncontrôlées par le
compilateur
=> Pas de try/catch
Exception
RuntimeException
XXXException
YYYException
F. Mallet - POO
15
Exceptions, Assertions
Exemples
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
F. Mallet - POO
16
Exceptions, Assertions
Exceptions contrôlées
Toutes les exceptions sont de type Throwable
Throwable
Error
Exception
RuntimeException
XXXException
Exceptions contrôlées
=> try/catch obligatoire
F. Mallet - POO
17
Exceptions, Assertions
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
F. Mallet - POO
18
Exceptions, Assertions
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 Exception
Peut avoir à instancier un nouvel objet
Exemple:
class XXX implements Iterator<X> {
@Override
public void remove() {
throw new UnsupportedOperationException("…");
}
}
F. Mallet - POO
19
Exceptions, Assertions
Exemple: CompteBancaire
Le crédit d’un montant négatif n’est pas prévu
class CompteBancaire {
int solde = 0;
void créditer(int somme) {
if (somme<0)
throw new IllegalArgumentException("somme négative
illégale!");
solde += somme;
}
}
Note:
IllegalArgumentException est une
F. Mallet - POO
RuntimeException
20
Exceptions, Assertions
Définir ses propres exceptions
Exception non-contrôlée
class DécouvertException extends RuntimeException {
CompteBancaire compte;
DécouvertException(CompteBancaire c) {
super("Découvert non autorisé sur "+c);
this.compte = c;
}
}
Usage
class CompteBancaire {
int solde = 0;
void débiter(int somme) {
if (somme>solde)
throw new DécouvertException(this);
solde -= somme;
}
}
F. Mallet - POO
21
Exceptions, Assertions
Exception 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)
F. Mallet - POO
22
Exceptions, Assertions
Exceptions dans les constructeurs
Si une exception est levée dans un constructeur
Et qu’elle n’est pas attrapée
Alors aucune instance n’est créée
F. Mallet - POO
23
Exceptions, Assertions
Définir ses propres exceptions
Exception contrôlée
class DécouvertException extends Exception {
CompteBancaire compte;
DécouvertException(CompteBancaire c) {
super("Découvert non autorisé sur "+c);
this.compte = c;
}
}
Usage
class CompteBancaire {
int solde = 0;
void débiter(int somme) throws DécouvertException {
if (somme>solde)
throw new DécouvertException(this);
solde -= somme;
}
}
F. Mallet - POO
24
Exceptions, Assertions
Pré et Post-conditions
LES ASSERTIONS
F. Mallet - POO
25
Exceptions, Assertions
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)
F. Mallet - POO
26
Exceptions, Assertions
Exemple: CompteBancaire
Le crédit d’un montant négatif n’est pas prévu
class CompteBancaire {
int solde = 0;
void créditer(int somme) {
assert(somme>=0): "somme négative illégale :"+somme;
solde += somme;
}
}
Note:
En général, ce sera garanti par l’interface graphique (pas
encore disponible)
F. Mallet - POO
27
Exceptions, Assertions
Activation
Activation
Lors de la compilation (période de test)
• Si on n’active pas, le code est ignoré (pas dans le bytecode)
• Si on l’active, on peut choisir ou non de l’exécuter
Lors de l’exécution
• Si elles ont été activées à la compilation
• Si on n’active pas, 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
F. Mallet - POO
28
Exceptions, Assertions
Activation: compilation
Pour activer les assertions
javac –source 1.4
F. Mallet - POO
29
Exceptions, Assertions
Activation: exécution
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>
F. Mallet - POO
30
Exceptions, Assertions
Activation: exécution
Pour activer les assertions systèmes
java –esa
Pour désactiver les assertions systèmes
java –dsa
F. Mallet - POO
31
Exceptions, Assertions
Pas une bonne idée pour un assert !
Exception contrôlée
class DécouvertException extends Exception {
CompteBancaire compte;
DécouvertException(CompteBancaire c) {
super("Découvert non autorisé sur "+c);
this.compte = c;
}
}
Usage
class CompteBancaire {
int solde = 0;
void débiter(int somme) throws DécouvertException {
if (somme>solde)
throw new DécouvertException(this);
solde -= somme;
}
}
F. Mallet - POO
32
Exceptions, Assertions
Compléments et nouveautés du JDK 7
EXCEPTIONS - COMPLÉMENTS
F. Mallet - POO
33
Exceptions, Assertions
Synopsis: multi-catch
try {
// fonctionnement normal
…
} catch (XXXException | YYYException e) {
// cas si XXXException ou YYYException se produit
}
Attention: [Depuis JDK1.7]
e est final
XXXException : pas un sous-type de YYYException
YYYException : pas un sous-type de XXXException
Même comportement dans les deux cas !
Tentative pour éviter try { } catch(Exception e)
F. Mallet - POO
{ }
34
Exceptions, Assertions
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
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
F. Mallet - POO
35
Exceptions, Assertions
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)
F. Mallet - POO
36
Exceptions, Assertions
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 pas 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
F. Mallet - POO
37
Exceptions, Assertions
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
F. Mallet - POO
38
Exceptions, Assertions
Automatic Resource Management
Depuis le JDK 7
Enumération des ressources qui doivent être fermées
automatiquement
try ( Déclaration des ressources à fermer ) {
// fonctionnement normal
…
}
F. Mallet - POO
39
Exceptions, Assertions
ARM: avant
import java.io.*;
public class Lecture {
static public void main(String[] args) {
try {
FileReader fr = new FileReader("fic.txt");
BufferedReader br = new BufferedReader(fr);
String ligne = null;
do {
ligne = br.readLine();
if (ligne == null) break;
System.out.println(ligne);
} while(true);
br.close();
} catch(Exception ex) {
System.err.println("Erreur de lecture : "+ex);
}
}
}
Si une exception se produit la ressource br n’est pas fermée
F. Mallet - POO
40
Exceptions, Assertions
ARM: avant
import java.io.*;
public class Lecture {
static public void main(String[] args) {
try {
FileReader fr = new FileReader("fic.txt");
BufferedReader br = new BufferedReader(fr);
String ligne = null;
do {
ligne = br.readLine();
System.out.println(ligne);
} while(ligne != null);
} catch(Exception ex) {
System.err.println("Erreur de lecture : "+ex);
} finally { br.close(); }
}
}
Est illégal car br n’est visible que dans le bloc try !
F. Mallet - POO
41
Exceptions, Assertions
ARM: avant
import java.io.*;
public class Lecture {
static public void main(String[] args) {
FileReader fr = new FileReader("fic.txt");
BufferedReader br = new BufferedReader(fr);
try {
String ligne = null;
do {
ligne = br.readLine();
System.out.println(ligne);
} while(ligne != null);
} catch(Exception ex) {
System.err.println("Erreur de lecture : "+ex);
} finally { br.close(); }
}
}
Est illégal car new FileReader peut lever une exception !
2 blocs try !
F. Mallet - POO
42
Exceptions, Assertions
ARM: après
import java.io.*;
public class Lecture {
static public void main(String[] args)
throws FileNotFoundException, IOException {
try (
FileReader fr = new FileReader("fic.txt");
BufferedReader br = new BufferedReader(fr) ;
) {
String ligne = null;
do {
ligne = br.readLine();
System.out.println(ligne);
} while(ligne != null);
}
}
}
Le close est appelé automatiquement sur fr et br
Pas si la ressource est déjà fermée !
F. Mallet - POO
43
Exceptions, Assertions
ARM : après
Les ressources déclarées font parties de la clause try
Les exceptions levées sont après le catch qui suit
try (
FileReader fr = new FileReader("fic.txt");
BufferedReader br = new BufferedReader(fr)
) {
} catch (FileNotFoundException fnfe) { … }
Mais la méthode close() est appelée quoi qu’il
arrive
D’une façon similaire au finally
Les variables déclarées ici doivent être d’un type qui
réalise l’interface java.lang.AutoCloseable
F. Mallet - POO
44
Exceptions, Assertions
java.io.Closeable - java.lang.AutoCloseable
java.lang.AutoCloseable
public interface AutoCloseable {
// close doit être idempotent (+s close == 1 seul close)
void close() throws Exception;
}
java.io.Closeable
public interface Closeable
extends AutoCloseable{
// pas nécessairement idempotent mais recommandé
void close() throws IOException;
}
F. Mallet - POO
45