Exceptions
On peut découvrir les erreurs dans un
programme
pendant:
La
compilation
L'exécution
Langages comme C traitent les erreurs en utilisant des mots de statut - il faut les vérifier pendant l'exécution du programme.
Deux risques dans cette approche:
- de ne pas
vérifier tous les fautes possibles (ça ne peut arriver
que
à d'autres)
- de
convertir
le programme dans un cauchemar illisible des vérifications
Dans la POO on a choisi une autre approche – la classe Throwable.
La hiérarchie des erreurs
Les exceptions changent la séquence d'exécution, quand il arrive un événement important ou inattendu, habituellement une erreur. Elles donnent le contrôle à des autres parties du programme qui font l’effort de réagir convenable a ces erreurs.
Les atouts de cette approche :
- On n’a plus besoin de
vérifier
tous les points cruciaux. Tous ce qu’on doit faire c’est de
gérer
le problème à une place spéciale nommée
«
exception handler ». Comme ça on peut séparer le
code
de ce qu’on veut faire du code du problème et faire le
programme
plus lisible.
- On n’est pas obligé
de savoir
comment gérer le problème sur place. Dans ce cas on peut
« jeter (throw) une exception » et laisser la
décision
quoi faire à un autre contexte du programme.
|
|
Erreur pendant l'exécution du programme |
|
Causer une exception (jeter une exception) |
|
Rattraper une exception et aller a une autre partie du programme afin de résoudre le problème |
|
La partie du programme qui fait ca |
|
La séquence des ``call statement`` qui finit par méthode dans laquelle a eu lieu l’exception |
|
Quelques exceptions prédéfinies:
Exception
ClassNotFoundException
IllegalAccessException
InterrupredException
NoSuchMethodException
RuntimeException
ArithmeticException
ArrayStoreException
ClassCastException
NegativeArraysizeException
NullPointerException
SecurityException
IndexOutOfBoundsException
String IndexOutOfBoundsException
Array IndexOutOfBoundsException
IllegalArgumentException
NumberFormatException
IllegalThreadStateException
Throwing
Supposons que l'objet 'q' n'est pas encore
initié.
On peut verifié ça avant d'utliser l'objet et laisser
traitement
de la situation dans un autre contexte:
if( q = = null)
throw new
MyNullPointerException();
Comme ça on peut ne pas s'occuper traitement de la situation.
On peut jeter une exception avec un argument (chaîne des caractères):
if(q == null)
throw new
MyNullPointerException("q
= null");
Tous les exceptions ont deux constructeurs – le premier c’est le constructeur par défaut (sans arguments) et le deuxième c’est avec un argument – chaîne des caractères qui peut être analyser dans l’ »exception handler »
Si une exception est jetée dans une méthode, il se produit la procedure suivante :
Call stack
|
Recherche d'un try/catch bloc
|
On peut introduire dans le programme des blocs surveillés:
try {
//code
surveillé
qui peut générer des exceptions
}
catch(type1 id1) { // on peut avoir zero ou
plusieurs
"catching" blocs
//traite
les exceptions de type type1 dans le bloc surveillé
}
catch(type2 id2) {
//traite
les exceptions de type type2
}…
finally { //on peut avoir zero ou un "finally"
blocs
//toujours
executé, aucune importance s'il y a eu lieu exception ou pas
}
S'il n'existe pas de bloc try/catch ou bien il existe mais n'existe pas d'instruction catch qui corresponde à l'exception levée, l'exception est envoyée à la méthode appelante et ainsi de suite jusqu'à ce qu'elle sera capturée.
Les traitement blocs("catch blocs") doivent apparaître immédiatement après le « try » bloc
Regles
1. Chaque try bloc peut avoir
zéro, un, ou plusieurs catch blocs, mais seulemnt un
finally bloc.
2. Les catch et finally blocs peuvent exister
seulement s'ils sont liés avec un try bloc correspondant.
3. Chaque try bloc doit avoir au moin un catch
ou bien un finally bloc.
4. L'ordre des catch blocs doit aller de plus spécifique vers
plus generale.
Terminaison ou bien prolongation
Il y a deux approches dans la théorie des exception. Le premier (adopté en Java) accepte que les erreurs sont graves et qu’on doit terminer l’exécution du programme. Donc jeter une exception habituellement a pour résultat terminaison de l’exécution de la méthode concernée.
Le deuxième accepte qu’après le traitement de l’exception on peut continuer le programme("resumption"). Pour réaliser le deuxième approche en Java il faut prendre des précautions spéciales (introduire « try-catch » bloc à la place de l’erreur et s’il faut mettre tous ça dans « while » clause).
Création des exceptions propres
On n'est pas obligé de se limiter avec les
exceptions
existantes. Les exceptions créées doivent étendre
l'exception le plus proche possible. Si on ne peut trouver une
exception
convenable on étends la classe Exception.
Exemples
L'addition des deux entiers :- Exception non prevue
import
java.awt.*; import java.awt.event.*; import javax.swing.*; public class Sum extends JFrame { JTextField textField1,textField2,rez; JLabel l; int value1=0,value2=0,sum=0; Sum(){ setLayout(new FlowLayout()); textField1 = new JTextField(5); textField2 = new JTextField(5); textField1.addActionListener(new Enter()); textField2.addActionListener(new Enter()); l = new JLabel(" Type a number in each box!"); add(l); rez= new JTextField(18); add(textField1); add(textField2); add(rez); textField1.setText("0"); textField2.setText("0"); setSize(230,150); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } class Enter implements ActionListener { public void actionPerformed(ActionEvent e) { value1= Integer.parseInt(textField1.getText()); value2= Integer.parseInt(textField2.getText()); rez.setText(value1+value2+""); } } public static void main(String arg[]){ new Sum(); } } |
- Exception saisie
import
java.awt.*; import java.awt.event.*; import javax.swing.*; public class SumEx extends JFrame { JTextField textField1,textField2,rez; JLabel l; int value1=0,value2=0,sum=0; SumEx(){ setLayout(new FlowLayout()); textField1 = new JTextField(5); textField2 = new JTextField(5); textField1.addActionListener(new Enter()); textField2.addActionListener(new Enter()); l = new JLabel(" Type a number in each box!"); add(l); rez= new JTextField(18); add(textField1); add(textField2); add(rez); textField1.setText("0"); textField2.setText("0"); setSize(230,150); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } class Enter implements ActionListener { public void actionPerformed(ActionEvent e) { String rz=""; try{ value1= Integer.parseInt(textField1.getText()); value2= Integer.parseInt(textField2.getText()); rz=value1+value2+""; } catch(NumberFormatException ex){ rz="integers in each box please!"; } finally{ rez.setText(rz); } } } public static void main(String arg[]){ new SumEx(); } } |
class
MonException extends Exception {} public class FinallyClause { static int count = 0; public static void main(String[] args) { while(true) { try { // Post-increment ( zero la première fois): if(count++ == 0) throw new MonException(); System.out.println("No exception"); } catch(MonException e) { System.out.println("MonException"); } finally { System.out.println("Dans /"finally clause/""); if(count == 2) break; // out of "while" } } } |
Créer son propre type d'exception - traité dans la fonction
class
NoNote extends Exception{ String message; NoNote(String message){ this.message = message; System.out.println(message); } } import java.util.*; public class Exc3 { static Scanner sc=new Scanner(System.in); public static void main(String arg[]){ System.out.println("Note: "+Note()); } static int Note(){ boolean ok; int note=200; do{ ok = true; System.out.print("next note:"); try{ String s= sc.nextLine(); note = Integer.parseInt(s); } catch(NumberFormatException ie){ System.out.println("Integer please!"); ok=false; continue; } try{ if((note>20)||(note <0)){ throw new NoNote("outside [0,20]"); } } catch(NoNote ex){ ok = false; } }while(!ok); return note; } } |
- traité hors la fonction
class
NoNote extends Exception{ String message; NoNote(String message){ this.message = message; System.out.println(message); } } import java.util.*; public class Exc4 { static Scanner sc=new Scanner(System.in); public static void main(String arg[]){ int note=0; //initialization boolean ok; do{ ok=true; try{ note = Note(); } catch(NoNote ex){ ok = false; } catch(NumberFormatException im){ ok=false; System.out.println ("Integer please"); } }while(!ok); System.out.println("Note: "+note); } static int Note() throws NoNote{ int note; System.out.print("next note:"); note = Integer.parseInt(sc.nextLine()); if((note>20)||(note <0)){ throw new NoNote("outside [0,20]"); } return note; } } |
Remarque
On
peut diviser les exceptions en deux catégories - "unchecked" et
"checked". Les premières sont des exceptions dont la classe de
base est "RuntimeException" (dérivée de "Exception"). Il
n'est pas obligatoire de gérer ces exceptions.
Exemple
- division à zéro sans traiter l'exception
ArithmeticException (elle est "unchecked").
public
class Exc1 {
public static void main(String arg[]){
System.out.println("rez:"+func(5,0));
}
static int func(int a, int b){
return a/b;
}
}
L'exception est traitée
public
class Exc2 {
public static void main(String arg[]){
try{
System.out.println("rez:"+func(5,0));
}
catch(ArithmeticException ex){
System.out.println("divide by
zero");
}
}
static int func(int a, int b){ return a/b; }
}
Par
contre le compilateur refusera systématiquement de
compiler une méthode capable de provoquer une "checked"
exception, si cette exception n'est pas rattrapée (par try/catch
) ou tout du moins signalée comme susceptible de
générer ce type d'exceptions (par le mot clé
throws).
static
int Note() throws NoNote{
Scanner sc = new Scanner(System.in);
int note;
System.out.print("next note:");
note = sc.nextInt();
if((note>6)||(note
<2))
throw new NoNote("outside [2,6]");
return note;
}
class Bull extends Exception { public String s; Bull(String par) { s = par; } } enum Age { YOUNG, ADULT } enum Sex { MALE, FEMALE } enum Run { FAST, SLOW } class Animal { private Age age; private Sex sex; Animal(Age age, Sex sex) { this.age = age; this.sex = sex; } public Age age() { return age; } public Sex sex() { return sex; } public String toString() { return " animal: " + age + ", " + sex; } } class Herbivore extends Animal { public Run run; Herbivore(Age age, Sex sex, Run run) { super(age, sex); this.run = run; } public String toString() { return super.toString() + ",herbivore:" + run; } } class Carnivore extends Animal { private boolean starving; Carnivore(Age age, Sex sex) { super(age, sex); starving = true; } public Herbivore[] tear(Herbivore[] herd) throws Bull, ArrayIndexOutOfBoundsException { if (starving) { if (herd[herd.length - 1].age() == Age.ADULT && herd[herd.length - 1].sex() == Sex.MALE) throw new Bull("BULL FOUND!!"); Herbivore[] buffer = new Herbivore[herd.length - 1]; System.arraycopy(herd, 0, buffer, 0, herd.length - 1); starving = false; return buffer; } return herd; } public void sleep() { starving = true; } public String toString() { return super.toString() + " wolf , starving:" + starving; } } public class MyException { public static void prt(Animal[] animal, Animal wolf) { System.out.println("\n\n\n animals: \n"); for (int i = 0; i < animal.length; i++) System.out.println("" + animal[i]); System.out.println("\n" + wolf); } public static void main(String[] arg) { Herbivore[] cows = new Herbivore[(int) (Math.random() * 10)]; for (int i = 0; i < cows.length; i++) { cows[i] = new Herbivore( Math.random() > 0.5 ? Age.YOUNG : Age.ADULT, Math.random() > 0.5 ? Sex.MALE : Sex.FEMALE, Math.random() > 0.5 ? Run.FAST : Run.SLOW); } Carnivore wolf = new Carnivore(Age.ADULT, Sex.MALE); prt(cows, wolf); for (;;) { try { cows = wolf.tear(cows); } catch (Bull e) { System.out.println(e.s); System.out.println("\nEnd of the program"); System.exit(1); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("NO MORE COWS!"); System.out.println("\nEnd of the program"); System.exit(1); } wolf.sleep(); prt(cows, wolf); } } } |
animals: animal: YOUNG, MALE,herbivore:FAST animal: YOUNG, FEMALE,herbivore:SLOW animal: YOUNG, MALE,herbivore:FAST animal: YOUNG, MALE,herbivore:SLOW animal: ADULT, MALE,herbivore:FAST animal: ADULT, MALE,herbivore:FAST animal: ADULT, MALE,herbivore:FAST animal: ADULT, FEMALE,herbivore:SLOW animal: ADULT, MALE wolf , starving:true animals: animal: YOUNG, MALE,herbivore:FAST animal: YOUNG, FEMALE,herbivore:SLOW animal: YOUNG, MALE,herbivore:FAST animal: YOUNG, MALE,herbivore:SLOW animal: ADULT, MALE,herbivore:FAST animal: ADULT, MALE,herbivore:FAST animal: ADULT, MALE,herbivore:FAST animal: ADULT, MALE wolf , starving:true BULL FOUND!! End of the program _____________________________ animals: |