Exceptions

Introduction

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.

Quelques notions:
 
Action
Notion
Erreur pendant l'exécution du programme
Exception
Causer une exception (jeter une exception)
Throwing
Rattraper une exception et aller a une autre partie du programme afin de résoudre le problème
Catching
La partie du programme qui fait ca
Catchblock
La séquence des ``call statement`` qui finit par méthode dans laquelle a eu lieu l’exception 
Stack trace

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 :

Ça ressemble un peut de "return" normal de la méthode mais on peut aller beucoup plus haut dans le contexte de traitement du programme - ou l'exception correspondant est traité.
 


Call stack

Recherche d'un try/catch bloc


 

Catching

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();
    }
}

Finally clause exemple

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;
}


Un autre exemple

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:

 animal: ADULT, FEMALE,herbivore:SLOW

 animal: ADULT, MALE wolf , starving:true



 animals:


 animal: ADULT, MALE wolf , starving:true
NO MORE COWS!

End of the program