page précédantetable des matièrespage suivante

Изключения(exceptions)

Грешки в една програма могат да бъдат открити :
        - по време на компилация или
        - по време на изпълнение

Езици като C обработват грешките като използват дума на състоянието, която трябва да бъде проверяване по време на изпълнението на програмата.

Този подход крие два риска:
        - да не се проверяват всички възможни грешки
        - да се обърне програмата в кошмар от проверки

В обектно-ориентираното програмиране е избран един друг подход - обработка на изключения. Изключенията сменят последователността на изпълнение на инструкциите, при наличие на неочаквано събитие, обикновено грешка. В този случай управлението се предава на друга част от програмата, която прави опит да реагира адекватно на грешката.

Предимства на подхода:
     - Не е необходима проверка на всички критични точки в програмата. Всичко, което трябва да се направи е да се опише възможната реакция на програмата на специално място на речено  « exception handler» По този начин може да се отдели кода на програмата от обработката на възможните проблеми и да се направи по - четлива.
    - Не е необходимо вземането на решение в текущия контекст. В този случай може да се генерира (throw) изключение и да се остави решението на друг контекст от програмата.

Няколко понятия:
 

Действие

Понятие

Грешка по време на изпълнението на програмата
Exception
Генериране на изключение
Throwing
Прихващане на изключение в друга част от програмата
Catching
Програмния код за обработка на изключението
Catchblock
Последователността от ``call statement`` , която завършва с метода където е генерирано изключението
Stack trace

Няколко предефинирани изключения:

Exception

    ClassNotFoundException

    IllegalAccessException

    InterrupredException

    NoSuchMethodException

    RuntimeException

        ArithmeticException

        ArrayStoreException

        ClassCastException

        NegativeArraysizeException

        NullPointerException

        SecurityException

        IndexOutOfBoundsException

        String IndexOutOfBoundsException

        Array IndexOutOfBoundsException

        IllegalArgumentException

        NumberFormatException

        IllegalThreadStateException
 

Генериране на изключение(Throwing)
Нека обекта 'q' да не е още инициализиран. Този факт може да се провери преди използването на обекта и обработката на ситуацията да се остави на друг контекст на програмата:

    if( q = = null)
        throw new NullPointerException();

Възможно е генерирането на изключение посредством конструктор с един аргумент(низ от символи):

    if(q == null)
        throw new NullPointerException("q = null");

Всички изключения имат по два конструктора - първият е подразбиращият се конструктор(без аргументи), а вторият е с един аргумент - низ от символи, който може да бъде анализиран в кода за обработка на изключението (exception handler ).

Когато в даден метод се генерира изключение се извършват следните действия :

 Обработка на изключенията(Catching)

В програмата могат да се въведат "проследявани" блокове:

try {
        //опасен проследяван код, който може да предизвика изключение
}

catch(type1 id1) { // може да има нула или повече "catch" блокове
        //обработва изключения от тип "type1" в проследявания блок
}
catch(type2 id2) {
        //обработва изключения от тип "type2"
}…

finally { //може да има нула или повече  "finally" блокове
        //изпълнява се винаги, независимо дали има изключение или не
}

Обработващите блокове ("catch blocs") трябва да се намират непосредствено след « try » блока

Прекратяване или продължаване

Има два подхода в теорията на изключенията. Първият (възприет в Java) приема че изключенията представят сериозни грешки и изпълнението на програмата трябва да се прекрати. Следователно генерирането на изключение причинява обикновено прекратяването на засегнатия метод.

Вторият подход приема, че след обработката на изключението, може да се продължи изпълнението на метода ("resumption"). Вторият подход се реализира на  Java чрез подходящо избран « try-catch » блок обхващащ кода където се появява грешката и ако трябва всичко може да се сложи в « while » клауза.

Прост пример: Сумиране на две цели числа- без предвидено изключение
 
 
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();
    }
}
   

 
Сумиране на две цели числа - изключението е прихванато
  
 
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();
    }
}

Създаване на собствени изключения
Потребителят може да създава собствени изключения чрез наследяване на съществуващи. Създаваните изключения трябва да наследяват най-близкия по смисъл клас. Ако има колебание се използва директно класът  Exception.




finally clause
class MyException extends Exception {}

public class FinallyClause {
  static int count = 0;
  public static void main(String[] args) {
    while(true) {
      try {
        // Post-increment ( zero first time):
        if(count++ == 0)
          throw new MyException();
        System.out.println("No exception");
      } catch(MyException e) {
        System.out.println("MyException");
      } finally {
        System.out.println("in  /"finally clause/"");
        if(count == 2) break; // out of "while"
      }
    }
  }

MyException
in  "finally clause"
No exception
in finally clause"

 




Собствено изключение - прихванато във функцията където възниква

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

Собствено изключение - прихванато извън функцията където възниква

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

Илюстративен пример
 

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.exit(1);
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println("NO MORE COWS!");
System.exit(1);
}
wolf .sleep();
prt(cows,wolf );
}
}
}
 animals:

 animal: ADULT, FEMALE,herbivore:FAST
 animal: YOUNG, FEMALE,herbivore:FAST
 animal: ADULT, MALE,herbivore:SLOW
 animal: ADULT, MALE,herbivore:FAST
 animal: ADULT, FEMALE,herbivore:FAST
 animal: ADULT, FEMALE,herbivore:SLOW

 animal: ADULT, MALE wolf , starving:true

 animals:

 animal: ADULT, FEMALE,herbivore:FAST
 animal: YOUNG, FEMALE,herbivore:FAST
 animal: ADULT, MALE,herbivore:SLOW
 animal: ADULT, MALE,herbivore:FAST
 animal: ADULT, FEMALE,herbivore:FAST

 animal: ADULT, MALE wolf , starving:true

 animals:

 animal: ADULT, FEMALE,herbivore:FAST
 animal: YOUNG, FEMALE,herbivore:FAST
 animal: ADULT, MALE,herbivore:SLOW
 animal: ADULT, MALE,herbivore:FAST

 animal: ADULT, MALE wolf , starving:true
BULL FOUND!!

_____________________________

  animals:

 animal: YOUNG, MALE,herbivore:SLOW
 animal: YOUNG, FEMALE,herbivore:SLOW
 animal: YOUNG, FEMALE,herbivore:SLOW
 animal: YOUNG, FEMALE,herbivore:SLOW

 animal: ADULT, MALE wolf , starving:true

 animals: 

 animal: YOUNG, MALE,herbivore:SLOW
 animal: YOUNG, FEMALE,herbivore:SLOW
 animal: YOUNG, FEMALE,herbivore:SLOW

 animal: ADULT, MALE wolf , starving:true

 animals:
 animal: YOUNG, MALE,herbivore:SLOW
 animal: YOUNG, FEMALE,herbivore:SLOW

 animal: ADULT, MALE wolf , starving:true

 animals:

 animal: YOUNG, MALE,herbivore:SLOW

 animal: ADULT, MALE wolf , starving:true

 animals:

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

page précédantetable des matièrespage suivante