520 likes | 624 Views
Gestion des exceptions E/S. Problèmes des erreurs dans les programmes. erreur matérielle (imprimante débranchée, serveur en panne), contrainte physique (disque plein), erreurs de programmation (cas non prévu par le programme, division par zéro, ouverture d’un fichier qui n’existe pas),
E N D
Problèmes des erreurs dans les programmes • erreur matérielle (imprimante débranchée, serveur en panne), • contrainte physique (disque plein), • erreurs de programmation (cas non prévu par le programme, division par zéro, ouverture d’un fichier qui n’existe pas), • utilisateur récalcitrant (type de données rentrées par l’utilisateur incorrect)
En cas de problèmes • envoyer un message d’erreur, • sauvegarder l’ensemble du travail en cours, • permettre une sortie correcte du programme, • revenir en arrière et effectuer un autre traitement.
Comment faire • Solution : tout prévoir (tester l’égalité à zéro du dénominateur avant une division, etc.) • Problème : vous avez beau être un bon programmeur vous ne pouvez pas tout contrôler • que faire dans le cas d’un mauvais type en entrée, ou pour les cas non prévus par le programme ?
Exceptions • 2 familles d’exceptions: • non fatales • fatales (provoquent l’arrêt du programme).
Hiérarchie des exceptions Object Throwable Exception Error RunTimeException IOException …
Une exception est un objet de type Exception • Instancier par n’importe quelle sous-classe d’Exception • Hiérarchie RuntimeException et Error • Une hiérarchie d’exceptions non contrôlées par le compilateur
Hiérarchie error: erreurs graves • Exemples • NoSuchMethodError: la méthode référencée n’est pas accessible • StackOverflowError: débordement de pile
Hiérarchie RuntimeException • Exemples • ArithmeticException: une erreur arithmétique (division par 0…) • IndexOutofBoundsException: indice d’un tableau est en dehors des bornes autorisées.
Il n’est pas obligatoire de gérer les exceptions de type RuntimeException public class ZeroDivide { static public void main(String[] args) { int a = 3; int b = 0; System.out.println("Resultat de la division : " + a/b); } } • Ce code se compile mais une exception apparaît au niveau de l’exécution et le programme s’arête. • Une ArithmeticException est une RuntimeException. • Les RuntimeException ne sont pas vérifiées par le compilateur
Les autres exceptions doivent être prise en compte public class TaperTouche { static public void main(String[] args) { System.out.println("Tapez une touche pour terminer le programme"); System.in.read(); } } • Ce code ne compile pas parce que la méthode read() est susceptible de lever une exception de type IOException
L’appel d’une méthode qui lance une exception (une méthode qui déclare qu’elle lance une exception) doit être pris en compte dans le code appelant • Encapsuler l’appel dans un bloc try/catch
Contrôle de flot dans les blocs Try/catch Si le bloc Try réussit • Try { Instruction 1; // dans cette instruction il y a une possibilité de levée d’exception Instruction i } catch (Exception ex) { Instruction j; } Instruction k; 1 2
Contrôle de flot dans les bloc Try/catch Si le bloc Try échoue • Try { Instruction 1; // dans cette instruction il y a une possibilité de levée d’exception Instruction i } catch (Exception ex) { Instruction j; } Instruction k; 1 2 3
Try { Instruction 1; Instruction i; } catch (Exception ex) { Instruction j; } finally { Instruction k; } Try { Instruction 1; Instruction i; Instruction k; } catch (Exception ex) { Instruction j; Instructionk; } Finally pour ce qui s’exécute dans tous les cas Remarque: si le bloc try/catch a une instruction return finally s’exécute quand même Le flot saute à finally puis revient à return
Extrait de la documentation de la classe read • Method Detail read • public abstract int read() throws IOException • Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown. A subclass must provide an implementation of this method. • Returns: • the next byte of data, or -1 if the end of the stream is reached. • Throws: • IOException - if an I/O error occurs.
Deux manières de gérer les exceptions: la prendre en compte ou l’esquiver import java.io.IOException; public class TaperTouche { static public void main(String[] args) { System.out.println("Tapez une touche pour terminer le programme"); try { System.in.read(); } catch(IOException e) { System.out.println("Une IOException a été détecté !"); } } }
Il s’agit de déclarer que vous lancez l’exception même si techniquement ce n’est pas vous qui la lancez public class TaperTouche { static public void main(String[] args) throws IOException { System.out.println("Tapez une touche pour terminer le programme"); System.in.read(); } } L’esquiver
public class TaperTouche { static public void LireClavier throws IOException { System.out.println("Tapez une touche pour terminer le programme"); System.in.read(); } } Public class Main { static public void main(String[] args) throws IOException { TaperTouche.LireClavier(); } • Si Main n’esquive pas l’exception ou ne l’encapsule pas dans un bloc try/catch il y a une erreur de compilation.
Une RunTime exception peut être également intercepter et déclarer public class ZeroDivide { static public void main(String[] args) { int a = 3; int b = 0; try { System.out.println("Resultat de la division : " + a/b); System.out.println("Instructions suivant la division..."); } catch(ArithmeticException e) { System.out.println("Une exception s’est produite ! (ArithmeticException)"); } System.out.println("Instructions qui suivent le bloc catch..."); } } • Maintenant, le division par zéro ne provoque pas la terminaison du programme.
Créer ses propres classes d’exception • Imposer à la classe de dériver de la classe standard Exception • Exemple transmission d’un message au gestionnaire d’exception sous forme d’une information de type chaîne. • La classe Exception dispose d’un constructeur à un argument de type String dont on peut récupérer la valeur à l’aide de la méthode getMessage.
class MonZeroException extends Exception { public MonZeroException(String e){ super(e); } } public class laClauseThrows { public static void main (String[] args){ try{ System.out.println("je verifie le nombre donne en argument."); LaClauseThrows.test(args); } catch (MonZeroException e){ System.out.println(e.getMessage()); // getMessage méthode de la classe Throwable // e.printStackTrace(); méthode de la classe Throwable affiche l’état de la pile d’appels } } public static void test(String [] args) throws MonZeroException{ int n=Integer.parseInt(args[0]); if (n==0) throw new MonZeroException("j’ai vu un zero"); System.out.println("il n’y a pas eu d’exception pour zero"); } } }
Exemple transmission d’information au constructeur de l’objet exception class Point { private int x,y; public Point(int x, int y) throws ErrConst { if ((x<0) || (y<0)) throw new ErrConst(x,y); this.x =x; this.y=y; } public void affiche() { System.out.println("Coordonnées:" +x+" "+y); } } class ErrConst extends Exception { public int abs; public int ord; ErrConst (int abs, int ord) { this.abs = abs; this.ord=ord; } } public class Exoinfo1 { public static void main (String args[]) { try { Point a = new Point (1,4); a.affiche(); a = new Point (-3,5); a.affiche(); } catch (ErrConst e) { System.out.println("Erreur construction point"); System.out.println("coordonnees souhaitées"+e.abs+" "+e.ord); System.exit(-1); } } }
Exercice public class TestExceptions { public static void main (String [] args) { String test = "non"; try { System.out.println("Début de try"); prendreRisque(test); System.out.println("Fin de try"); } catch (HorribleException he) { System.out.println("Horrible exception"); } finally { System.out.println("finally"); } System.out.println("fin de main"); } static void prendreRisque(String test) throws HorribleExeception { System.out.println("début de risque"); if ("oui".equals(test)) { throw new HorribleException(); } System.out.println("fin de risque"); return; } } Quel est le résultat quand test vaut « non » et quand test vaut « oui »?
public class plusieursCatchs { public static void main (String[] args){ try{ System.out.println("je verifie le nombre donne en argument."); int n=Integer.parseInt(args[0]); if (n==0) throw new ZeroException(""); if (n>0) throw new SupAZeroException(""); if (n<0) throw new InfAZeroException(""); } catch (ZeroException e){ System.out.println("le nombre etait nul"); } catch (SupAZeroException e){ System.out.println("le nombre etait superieur a zero"); } catch (InfAZeroException e){ System.out.println("le nombre etait inferieur a zero"); } } } Les blocs catch doivent être ordonnés du plus petit au plus grand Cela dépend de la hiérarchie d’héritage Gérer plusieurs types d’exceptions
public class ZeroException extends Exception {} public class SupAZeroException extends Exception {} public class InfAZeroException extends Exception {}
Conclusion • La gestion des exceptions permet de dissocier le programme principal de la gestion des erreurs, ou des arrêts brusques du programme. • Ce n’est pas une nouvelle structure de contrôle en plus des if, while, for, switch. • La gestion des erreurs ralentit considérablement la vitesse du programme • Les exceptions doivent rester exceptionnelles!
E/S En Java, les échanges de données entre un programme et l’extérieur (autre programme, fichier, réseau) sont effectués par un « flot ou flux (streams en anglais) » de données • Un flot permet de transporter (le plus souvent) séquentiellement des données. Les données sont transportées une par une (ou groupe par groupe), de la première à la dernière donnée
Le cycle d’utilisation de lecture ou écriture séquentielle d’un flot de données est le suivant : • 1) Ouverture du flot • 2) Tant qu’il y a des données à lire (ou à • écrire), on lit (ou on écrit) la donnée suivante dans le flot • 3) Fermeture du flot
Sources ou destinations de flots • Fichier • Socket pour échanger des données sur un réseau • Données de grandes tailles dans une base de données (images, par exemple) • Pipe entre 2 files d’exécution • Tableau d’octets • Chaîne de caractères • URL (adresse Web) etc...
L’API d’E/S JAVA comprend des flots • de communication qui représentent des destinations et des sources (fichiers, socket réseau…) • de traitement ne fonctionne que s’ils sont chaînés à d’autres flots
Flux d’entrée clavier • Pour lire un caractère au clavier : • System.in.read(); • qui renvoie une valeur de type byte que l’on convertira en caractère par un opérateur cast. • char c = (char)System.in.read();
Pour arriver à lire un mot en entier, et s’arrêter après que l’utilisateur ait tapé “return”. char c; String chaine = ""; while ((c = (char)System.in.read()) != ’\n’) chaine=chaine+c; • Ou char c; StringBuffer chaine = new StringBuffer(); while ((c = (char)System.in.read()) != ’\n’) chaine.append(c); • ou Scanner sc = new Scanner(System.in); // classe Scanner System.out.println(sc.next());
Flux de fichier • Classe java.io.File • Représente un fichier sur le disque mais ne représente pas son contenu • Plus précisément un objet file représente le nom et le chemin d’un fichier ou d’un répertoire sur le disque • /E/COURS/JAVA/Jeu.txt • Java distingue les flux binaires des flux textes
Exemple d’utilisation d’un objet file • Créer un objet représentant un fichier existant • File f = new File(’’Monprog.txt’’); • Créer un répertoire • File rep = new File(’’JAVA’’); • Rep.mkdir(); • Obtenir le chemin absolu d’un fichier ou d’un répertoire • System.out.println(rep.getAbsolutePath()); • …
import java.util.*; import java.io.*; public class Lecture_Fichier { public static void main(String[] args) throws IOException{ Scanner sc = new Scanner(System.in); System.out.println("Entrez le repertoire ou se trouve le fichier : "); String dirBuf = sc.next(); File dir=new File(dirBuf); System.out.println("Entrez le nom du fichier : "); String fileBuf; fileBuf = sc.next(); File fil = new File(dir,fileBuf); if (fil.exists()) { System.out.println("Fichier trouvé"); System.out.println("Nom du fichier : "+fil.getName()); System.out.println("Chemin du fichier : "+fil.getPath()); System.out.println("Chemin absolu : "+fil.getAbsolutePath()); System.out.println("Droit de lecture : "+fil.canRead()); System.out.println("Droit d’écriture : "+fil.canWrite()); System.out.println("Fichier supprime : "+fil.delete()); // attention System.out.println("\n contenu du répertoire : "); String listing[] = dir.list(); for (int i=0; i<listing.length;i++) System.out.println(listing[i]); } else { System.out.println("Fichier absent"); } } }
import java.io.*; // dans cette partie on lit le nom du répertoire source public class copieFichier { public static void main(String args[]) throws java.io.IOException{ char ch; System.out.println("repertoire source : "); StringBuffer dirBuf = new StringBuffer(); while ((ch = (char)System.in.read()) != ’\n’) dirBuf.append(ch); File srcDir=new File(dirBuf.toString()); if (!srcDir.exists()) { System.out.println(" repertoire absent"); System.exit(1); } else if (!srcDir.canRead()){ System.out.println("repertoire illisible"); System.exit(1); } // dans cette partie on lit le nom du fichier source System.out.println("Entrez le nom du fichier source : "); StringBuffer fileBuf = new StringBuffer(); while ((ch = (char)System.in.read()) != ’\n’) fileBuf.append(ch); File srcFile = new File(srcDir,fileBuf.toString()); if (!srcFile.exists()) { System.out.println("fichier absent"); System.exit(1); } else if (!srcFile.canRead()){ System.out.println("fichier illisible"); System.exit(1); } Opération de copie d’un fichier dans un autre
// lecture du fichier destination System.out.println("Entrez le nom du fichier destination : "); fileBuf = new StringBuffer(); while ((ch = (char)System.in.read()) != ’\n’) fileBuf.append(ch); File dstFile = new File(srcDir,fileBuf.toString()); if (dstFile.exists()) { System.out.println("fichier existant"); System.exit(1); }
// ici on copie FileInputStream inStream = new FileInputStream(srcFile); FileOutputStream outStream = newFileOutputStream(dstFile); while (inStream.available()>0) // le nb d’octet % au pointeur de lecture outStream.write(inStream.read()); // écriture séquentielle d’un octet après l’autre inStream.close(); // on ferme le flux d’entrée outStream.close(); // on ferme le flux de sortie } } • FileInputStream, FileOutputStream resp. ouvre (crée) le fichier spécifié
Classe DataOutputStream • Les méthodes de la classe FileOutputStream sont rudimentaires • Envoyer sur le flux un octet ou un tableau d’octet • La classe DataOutputStream comporte des méthodes plus évoluées permettant d’envoyer sur un flux une valeur d’un type primitif quelconque ie writeInt, writeFloat… • DataOutputStream outStream = new DataOutputStream(new FileOutputStream(dstFile))
Exemple: création d’un fichier binaire: « toto.dat » import java.io.*; import java.util.*; public class Crsfic1 { public static void main(String args[]) throws IOException { String nomfich; Scanner sc = new Scanner(System.in); int n; DataOutputStream sortie = new DataOutputStream(new FileOutputStream("toto.dat")); do { System.out.print("donner un entier:"); n = sc.nextInt(); System.out.println("n="+n); if (n != 0) { sortie.writeInt(n); } } while (n != 0); sortie.close(); System.out.println("******* Fin de création ********"); } }
Lecture d’un fichier binaire import java.io.*; public class Lecfic1 { public static void main(String args[]) throws IOException { String nomfich; int n=0; DataInputStream entree = new DataInputStream(new FileInputStream("toto.dat")); boolean eof = false; while (!eof) { try { n = entree.readInt(); } catch (EOFException e) { eof = true; } if (!eof) System.out.println(n); } entree.close(); } }
Ecriture d’un fichier texte • Classe FileWriter permet de manipuler un flux texte associé à un fichier • Méthodes permettent d’écrire des caractères, chaînes • Classe PrintWriter possède des méthodes plus élaborées (print, println…)
import java.io.*; import java.util.*; public class Crstxt1 { public static void main(String args[]) throws IOException { String nomfich; Scanner sc = new Scanner(System.in); int n; PrintWriter sortie = new PrintWriter(new FileWriter("toto.txt")); do { System.out.print("donner un entier:"); n = sc.nextInt(); if (n != 0) { sortie.println(n+ " a pour carre"+n*n); } } while (n != 0); sortie.close(); System.out.println("******* Fin de création ********"); } }
Lecture d’un fichier texte import java.io.*; public class Lecftxt1 { public static void main(String args[]) throws IOException { String ligne; BufferedReader entree = new BufferedReader (new FileReader("toto.txt")); boolean eof = false; do { ligne = entree.readLine(); if (ligne != null) System.out.println(ligne); } while (ligne != null); entree.close(); } }
Les buffers • Ils fournissent un contenant temporaire pour grouper les données jusqu’à ce qu’il soit plein • Optimiser les échanges d’E/S • Méthode flush pour vidage immédiat du buffer (sinon le buffer est vidé quand il est plein) • Classes BufferedInput(Output)Stream pour les fichiers binaires • Classes BufferedReader(Writer) pour les fichiers texte
Classe StringTokenizer • Pour accéder à chacune des informations d’une même ligne • Classe StringTokenizer permet de découper une ligne en différents tokens en fonction d’un caractère séparateur
import java.util.*;import java.io.*; public class Main { public static void main(String args[]) throws IOException { double d, b; double p = 0; String n = null; String st = null; int i; StringTokenizer stt; BufferedReader in = new BufferedReader(new FileReader("in.txt")); d = Double.parseDouble(in.readLine().trim()); i = Integer.valueOf(in.readLine().trim()).intValue(); // ou Int.parseInt while ( (st = in.readLine()) != null) { stt = new StringTokenizer(st); p = Double.valueOf(stt.nextToken()).doubleValue(); b = Double.valueOf(stt.nextToken()).doubleValue(); n = stt.nextToken(); } in.close(); BufferedWriter out = new BufferedWriter(new FileWriter("out.txt")); out.write(n.toString()); out.newLine(); out.write(Double.toString(p)); out.flush(); out.close(); } }
Fichier in.txt 50.0 3 10 60 item1 20 100 item2 30 120 item3 Fichier out.txt Item3 30.0
Formatage des nombres • Le package java.text contient toutes sortes de méthodes de formatages • Classe NumberFormat se trouve dans ce package