Les fondements du langage Java
Chapitre 5
Exceptions et Fichiers
Pr. Mohammed OUANAN
LST Informatique 2015-2016 M. OUANAN
Erreurs et exceptions dans Java
♦ La détection des erreurs et leur traitement occupent une place importante dans un
programme. Tache fastidieuse et complexe dans les méthodes traditionnelles
(langages procédurales) qui retournent des codes d’erreurs (-1, 0, 1 …) code
peut devenir rapidement long et illisible
♦ Deux types d’erreurs: de compilation (syntaxiques) et erreurs au cours de
l’exécution (run-time) (problèmes d’accès aux données dans un fichier, ou sur le
réseau, accès BD ou serveur…)
♦ Quand une erreur surgit, un certain formalisme s’impose comme:
• notifier l’utilisateur de l’erreur et de son origine
• sauvegarder tout le travail déjà accompli ! (pas toujours facile si erreur)
• permettre à l’utilisateur de sortir du programme
-2-
Exemple
Considérons l’exemple de la classe point qui a:
- un constructeur a deux arguments qui permet de positionner le point dans le plan.
Test 1:
public class Point {
private int x, y;
public Point(int x, int y) {
if ((x < 0) || (y < 0)) { // Détection de l’erreur (l’Exception)
[Link]("Erreur de Construction"); /* traitement
en cas d’erreur (traitement de l’exception) */
[Link](-1);}
else {
this.x = x ; this.y = y; // traitement normal
}}} public class TestException {
Sortie du programme: public static void main(String[] argv) {
Exécution bien passée i=3 private int i=3;
Les appels de Point(6,1) et Point(3,4) // début du bloc susceptible de générer une exception
n’ont généré aucune exception.. Point a = new Point(6,1);
Point b = new Point(3, 4);
// Fin du bloc susceptible de générer une exception
[Link] (" Exécution bien passée i= "+i);
}} -3-
Test 2:
public class Point {
private int x, y;
public Point(int x, int y) {
if ((x < 0) || (y < 0)) { // Détection de l’erreur (l’Exception)
[Link]("Erreur de Construction");
/* traitementen cas d’erreur (traitement de l’exception) */
[Link](-1);}
else {
this.x = x ; this.y = y; // traitement normal
}}}
Sortie du programme:
public class TestException {
Erreur de Construction
public static void main(String[] argv) { L’appel de Point(6,1) n’a pas généré
private int i=3; d’exception, donc il a été exécuté
// début du bloc susceptible de générer une exception normalement.
Point a = new Point(6,1); Par contre l’appel de Point(-2,4) a généré
Point b = new Point(-2, 4); une exception et a provoqué l’arrêt du
// Fin du bloc susceptible de générer une exception programme (appel de [Link](-1);).
Par conséquent l’instruction
[Link] (" Exécution bien passée i= "+i);
[Link]() n’a pas été exécutée.
}}
Dans l’exemple précédent, le traitement normal, la détection de l’exception et son
traitement ne sont pas séparés. Java permet de séparer la détection de l’exception et de son
traitement. Le traitement normal et le traitement des exceptions sont dissociés.
-4-
La notion d’exception en Java
♦ Une exception est un signal
• qui indique que quelques chose d’exceptionnelle s’est produit (erreur!)
• qui interrompe le flot d’exécution normal du programme
♦ Pour traiter les erreurs, Java propose un mécanisme qualifié d'exception,
consistant à:
• imbriquer les instructions d’une méthode dans un bloc d'essai (le bloc try)
qui surveille l’exécution des instructions
• si une erreur surgit dans ce bloc, elle est levée ou signalée sous forme d'un
objet appelé Exception au bloc de traitement d'erreur (le bloc catch,
appelé gestionnaire d'exception)
-5-
Gestion d’exception en Java
Principe:
Lorsque une erreur a été détectée à un endroit, on la signale en « lançant » un
objet contenant toutes les informations que l’on souhaite donner sur l’erreur.
(« lancer»= créer un objet disponible pour le reste du programme)
À l’endroit où l’on souhaite gérer l’erreur (au moins partiellement) on peut
« attraper» (=utiliser) l’objet « lancé »
Si un objet « lancé» n’est pad attrapé du tout, cela provoque l’arrêt du
programme: toute erreur non gérée provoque l’arrêt,
Un tel mécanisme s’appelle « gestion des exceptions».
-6-
Syntaxe de la gestion d’exception
On cherche a remplir 4 tâches élémentaires:
1. Signaler une erreur
2. Marquer les endroits réceptifs aux erreurs
3. Leur associer ( à chaque endroit réceptif) un moyen de gérer les erreurs qui se
présentent,
4. Eventuellement, « faire le ménage» après un bloc réceptif aux erreurs
On a donc 4 mots du langages Java dédiez à la gestion des exceptions:
Throw: indique l’erreur (i,e, lance l’exception)
Try: indique un bloc réceptif aux erreurs
Catch: gère les erreurs associées (i.e. les attrape pour les traiter)
Finally: (optionnel) indique ce qu’il faut faire après un bloc réceptif
-7-
Présentation du traitement des exceptions
♦ En Java les exceptions sont des objets: toute exception doit être une instance
d’une sous-classe de la classe [Link]
-8-
Présentation du traitement des exceptions
Les exceptions constituent un arbre hiérarchique utilisant la notion d’héritage.
Object la classe racine de toutes les classes
Throwable getMessage(), toString(), printStackTrace(), etc.
Error erreurs graves, abandon du programme
Exception anomalies récupérables
RunTimeException erreur à l’exécution
ArithmeticException division par zéro par exemple
ClassCastException mauvaise conversion de classes (cast)
IndexOutOfBoundsException en dehors des limites (tableau)
NullPointerException référence nulle
IllegalArgumentException
NumberFormatException nombre mal formé
IOException erreurs d’entrées-sorties
FileNotFoundException fichier inconnu
Dans un catch, on peut capter l’exception à son niveau le plus général (Exception),
ou à un niveau plus bas (FileNotFoundException par exemple) de façon à avoir un
message plus approprié
-9-
Objets exceptions
♦ Les objets exceptions peuvent contenir des attributs particuliers et des méthodes
♦ Les attributs et méthodes standards définies dans [Link]:
- 10 -
Description des exceptions
♦ Structuration de la description des exceptions:
♦ On peut être amené à définir une hiérarchie de classes (sans nécessairement
définir de nouveaux attributs) uniquement dans un souci de structuration et de
typage des exceptions
- 11 -
Traitement des exceptions
♦ try {…} délimite un ensemble d’instructions susceptibles de déclencher une(des)
exceptions pour la(les)quelles une gestion est mis en œuvre
♦ Cette gestion est réalisée par des blocs catch (TypeDexception e) { …} qui suivent
le bloc try. Il permet ainsi d’intercepter (“attraper”) les exceptions dont le type est
spécifié et d’exécuter alors du code spécifique
- 12 -
Test:
public static void main(String[] argv) {
try { // dans ce bloc une exception peut se produire
Point b = new Point(-2, 4);
Point a = new Point(6, 1);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
// dans ce bloc on traite les exceptions
[Link]("Erreur de Construction");
[Link](-1);
}
[Link](" Excution bien passée");
}
}
Sortie du programme:
Erreur de Construction
L’appel de Point(-2,4); génère une exception, donc un saut est effectué vers le bloc
catch().
L’exécution du code du bloc catch() a provoqué l’arrêt du programme (appel de
[Link](-1);),
par conséquent l’appel de Point(6,1) et les instructions après le bloc try {} n’ont pas été
exécutées.
- 13 -
Traitement des exceptions
♦ Un bloc try est suivi par une ou plusieurs clauses catch qui permettent d'intercepter
("attraper") les exceptions dont le type est spécifié (dans la clause catch) et
d'exécuter alors du code spécifique
♦ Un seul bloc catch peut être exécuté, le premier susceptible d'attraper l'exception
• chaque clause catch doit être déclarée avec un argument de type Throwable ou
une sous-classe de Throwable
• quand une exception est levée dans le bloc try, la première clause catch dont le
type de l'argument correspond à celui de l'exception levée est invoquée
- clause catch dont l'argument est de même classe que l'exception levée,
- clause catch dont l'argument est une superclasse de classe de l'exception levée
♦ L'ordre des blocs catch est donc très important
- 14 -
Exemple de traitement des exceptions
- 15 -
Exemple de traitement des exceptions
- 16 -
Exemple de traitement des exceptions
- 17 -
Exemple de traitement des exceptions
- 18 -
Exemple de traitement des exceptions
♦ Il n'est pas nécessaire d'avoir une clause catch pour chaque type possible
d'exception pouvant être levée. Si aucun bloc catch ne permet d'attraper
l'exception, celle-ci est propagée vers la méthode appelante qui a alors la charge
de la traiter ou non
♦ Si une exception n'est attrapée par aucune des méthodes présentes dans la pile
des appels alors un message d'erreur ainsi que la trace de la pile d'appels sont
affichés et l'exécution du programme est interrompue
- 19 -
Finalisation
♦ Les clauses catch sont suivies de manière optionnelle par un bloc finally qui contient
du code qui sera exécuté quelle que soit la manière dont le bloc try a été quitté
♦ Le bloc finally permet de spécifier du code dont l'exécution est garantie quoi qu'il
arrive:
• le bloc try s'exécute normalement sans qu'aucune exception ne soit levé
• le bloc try lève une exception attrapée par l'un des blocs catch
• le bloc try lève une exception qui n'est attrapée par aucun des blocs catch
qui le suivent
- 20 -
Finalisation
♦ Le concept de finalisation a un intérêt double:
permet de rassembler dans un seul bloc un ensemble d'instructions qui autrement
•
auraient du être dupliquées
•permet d'effectuer des traitements après le bloc try, même si une exception a été
levée mais n’a pas été attrapée par les blocs catch
- 21 -
Lancement
♦ L'instruction throw (unObjetException) permet de lancer une exception.
unObjetException doit être une instance d'une sous-classe de Throwable
♦ Quand une exception est lancée:
1. l'exécution normale du programme est interrompue
2. JVM recherche la clause catch la plus proche permettant de traiter l'exception
lancée
3. cette recherche se propage au travers des blocs englobants et remonte les appels
de méthodes jusqu'à ce qu'un gestionnaire de l'exception soit trouvé
4. tous les blocs finally rencontrés au cours de cette propagation sont exécutés
Exemple:
public void Point (int x, int y) throws ErrConst {
// Déclare que le constructeur Point() peut générer une exception
if ((x <0) || (y<0)) throw new ErrConst();
// Détection de l’exception et Création d’une nouvelle valeur d’exception
this.x = x ; this.y = y; // traitement normal
}
ErrConst est une classe qui hérite de la classe Exception. Elle peut être définie de la manière
suivante:
class ErrConst extends Exception{
}
- 22 -
Lancement
♦ Toute méthode susceptible de lever une exception "normale" doit:
• soit l'attraper
•soit la déclarer explicitement, c'est à dire comporter dans sa signature l'indication
que l'exécution peut être provoquée: clause throws
♦ Les exceptions déclarées dans la clause throws d'une méthode sont:
• les exceptions levées dans la méthode et non attrapées par celle-ci
•les exceptions levées dans des méthodes appelées par la méthode et non
attrapées par celle-ci
- 23 -
Exemple de lancement
Problème ?
- 24 -
Exemple de lancement
- 25 -
Exemple de lancement
En Java, les exceptions qui peuvent être levées par une fonction doivent appartenir à la signature de la fonction. Mais, il
n'est pas obligatoire de les identifier précisement, il suffit que toutes les exceptions levées par la fonction soient
compatibles avec les exceptions déclarées dans la signature. La déclaration des exceptions dans la signature de la
fonction permet au compilateur Java, de vérifier que toutes les fonctions déclarent bien les exceptions qu'elles lèvent. Il
suffit de regarder le code de la fonction, de collecter les exceptions qui peuvent être levées par le code (ELLES sont
nécessairement dans la signature), d'enlever pour chaque bloc try celles qui sont capturées, puis de vérifier que les
exceptions restantes sont bien déclarées dans la signature de la fonction. - 26 -
Exemple de lancement
- 27 -
Entrée et sortie en Java
♦ L’entrée des données dans un programme ou la sortie des données d’un programme
sont assurées par les classes du package [Link]
♦ Le langage Java supporte les entrées et sorties de données par rapport à des
fichiers mais aussi via d’autres canaux comme la connexion réseau via les streams
(flux), On énuméré alors les classes suivantes:
- 28 -
Fichier Textes:Fonctions de lecture «classe FileReader»
Constructeur:
FileReader (String NomFichier)
FileReader f= new FileReader( ‘’[Link]’’);
Si le fichier n’existe pas l’ouverture déclenche une exception qui peut être attrapé
de la maniéré suivante:
try {
f= new FileReader( ‘’[Link]’’);
}
Catch ( Exception e){
[Link](″Erreur d’ouverture du fichier″);
[Link]([Link]());
[Link](0);
}
Méthodes:
- 29 -
Lecture d’un fichier texte caractère par caractère
Import [Link].*;
Class ES01{
public static void main ( String args[]) throws IOException
{
FileReader f=null;
try {
f= new FileReader( ‘’[Link]’’);
}
Catch ( Exception e){
[Link](″Erreur d’ouverture du fichier″);
[Link]([Link]());
[Link](0);
}
int c;
while(c=[Link]())!=-1) [Link]((char)c);
[Link]();
}
}
- 30 -
Lecture d’un fichier texte tampon par tampon
Import [Link].*;
Class ES02{
public static void main ( String args[]) throws IOException
{
FileReader f=null;
try {
f= new FileReader( ‘’[Link]’’);
}
catch ( Exception e){
[Link](″Erreur d’ouverture du fichier″);
[Link]([Link]());
[Link](0);
}
Char T[]=new char[100];
int n;
while(n=[Link](T))>0) {
String S=new String(T,0,n);
[Link](S);
}
[Link]();
}}
- 31 -
Fichier Textes: Fonctions d’écriture «classe File Writer »
Constructeur:
FileWriter (String NomDeFichier)
FileWriter f=new FileWriter(″test,dat″);
► Écrasement du contenu du fichier si existant
► Les erreurs d’ouverture peuvent aussi être détectées par l’intermédiaire
de la clause try….catch
Méthodes:
- 32 -
Exemple:
Import [Link].*;
Class ES03 {
public static void main ( String args[]) throws IOException
{ FileWriter f;
f= new FileWriter(’’[Link]’’);
[Link](’’ ceci est une chaine’’);
[Link](6);
[Link](’a’);
[Link](’’ 30.58’’);
float y= (float) 45.65;
String S=[Link](y);
[Link](S);//ou [Link](″″+y);
[Link]();
}
}
Autre fonctions de la classe FileReader
1-skip(long n); saut de n caractères. N doit etre un nombre positif;
2- close(); Fermeture de fichier
Autre fonctions de la classe FileReader
1- flish(); vider le tampon d’ecriture dans le fichier
2- close(); Fermeture du fuchier
- 33 -
Fichier texte: ouverture en mode en mode Mise à jour
Pour l’ajout, la modification , accès direct… on utilise la classe
« RandomAccessFile», celle-ci peut cependant être utilisée pour gérer aussi bien
les fichiers textes que les fichiers binaires,
Exemple:
Import java,io,*;
Class ES04{
Public static void main(String args []) throws IOException
{
RandomAccessFile f;
f=new RandomAccessFile (″test,dat″, ″rw″);
f,seek(f,lenght());
f,writeBytes(″ \r\nceci est une nouvelle ligne″);
f,write(20);
f,writeBytes(″ #″);
Int x=65;
f,write(x);
f,close();
}
} - 34 -
Fichiers binaires: classe RandomAccessFile
Constructeur:
RandomAccessFile (String NomFichier, String mode),
Avec mode une chaine de caractère qui précise le mode d’ouverture
Méthode d’accés:
accés direct:
accés indirect:
- 35 -
Fichier binaire: Méthode d’écriture
- 36 -
Exemple
Dans cet exemple, nous décrivons la même information (30,58) délimité
par les deux symboles < et > avec différents formats:
RandomAcessFile f;
f=new RandomAcessFile(″ tzst,dat″, ″rw″);
f,write(″ <″);
f,writeDouble(30.58);
[Link](″>\r\n <″);
[Link](″ 30.58″);
[Link](″>\r\n <″);
[Link](″ 30.58″);
[Link](″>″);
Le fichier crée aura le contenu suivant:
- 37 -
Fichier binaire : Méthode de lecture
- 38 -
Exemples
Exemple 1: lecture d’un fichier texte par tampon à l’aide d’une seule instruction
RandomAccessFile f=new RandomAcessFile(″[Link]″,″r″);
Int L=(int)f,length();// suppose que la taille du fichier est<32535
Byte T[]= new byte[L];
Int n = [Link](T);
String S=new String(T);
[Link](S);
[Link]();
Exemple2: lecture d’un fichier texte ligne par ligne
RandomAccessFile f=new RandomAcessFile(″[Link]″,″r″);
String Lingne;
Int n=0;
While(( Linge=f,readline())!=null)
[Link](Ligne);
[Link]();
- 39 -
Stockage des objets dans un fichier
♦ Java fournie des classes pour lire et écrire un objet et ses données comme une
unité cohésive (object streams). La sérialisation est le processus qui prend en
charge le décorticage de l’objet en un stream pour son écriture / lecture
♦ Un objet peut stocker des données primitives ou des références à d’autres objets.
Une classe peut stocker des données statiques. La sérialisation envoie
uniquement les données. Les données statiques ne sont pas sérialisées. la
définition de la classe n’est pas sérialisée, et tout champ marqué avec le mot clé
transient n’est pas sérialisé. Si des valeurs spécifiques d’un objet ne doivent
être sauvegardés dans un fichier, alors ces attributs doivent être marqués
comme transient
♦ Le marqueur d’interface Serializable désigne la classe et les objets de la classe
comme serializable. Le programmeur doit définir la classe comme
implémentant l’interface serializable. Uniquement les objets tagé Serializable
peuvent être sérialisés. Si la classe référence des objets d’une autre classe qui
n’est pas sérialisée, alors l’envoi de cette objet pour être stocké ne résultera pas
automatiquement au stockage de données de l’objet référencé
- 40 -
Fichiers binaires d’enregistrements -Persistance d’objets-
Classes utilisées:
ObjectInputStream: pour la lecture
ObjectOutputStream: pour l’écriture
Classe Mère:
- 41 -
Lecture et écriture d’un Objet
L’objet à lire ou à écrire doit appartenir à un objet sérialisable, la classe de
l’objet doit alors implémenter l’interface Serializable,
Exemple:
Class Produit implements Serializable{
Public String ref;
Public String desig;
Public double PU;
Public int QS;
Produit() {}
Produit (String ref, String desig, double PU, int QS){
This,ref=ref;
This,desig=desig;
This,PU =PU;
This,QS =QS;
}
}
Ecriture://serialisation
Produit p=new Produit(….);
FileOutputStream fos=new FileOutputStream (NomDeFichier);
ObjectOutputStream fout= new ObjectOutputStream (fos);
Fout,writeObject();
Lecure://Deserialisation
FileInputStream fis=new FileInputStream (NomDeFichier);
ObjectInputStream fin= new ObjectInputStream (fis);
Produit r= (Produit)[Link]();
- 42 -
Hiérarchie des classe Writer / Reader
♦ On utilise les classes Reader et
Writer pour lire et écrire des
séquences de caractères
♦ InputStreamReader et
OutputStreamWriter sont
utilisés pour les E/S du (au)
clavier
♦ FileReader et FileWriter sont
utilisés pour les E/S de
fichiers de caractères
♦ BufferedReader et
BufferedWriter sont utilisés
pour les E/S de fichiers
contenant des lignes de
caractères (méthodes
readLine, flush, newLine)
- 43 -