Tratarea erorilor

Excepţiile reprezintă mecanismul java folosit pentru tratarea erorilor ce apar în timpul execuţiei programelor. Excepţiile pot fi privite ca nişte evenimente ce pot fi generate şi tratate în timpul rulării unei aplicaţii. Excepţiile sunt modelate în java ca şi clase sub forma unei ierarhii ce are la bază clasa Throwable (vezi Figura 1).

Figura 1. Ierarhia claselor pentru tratarea exceptiilor.

În java există trei tipuri de erori: - clasa Error : modelează excepţii speciale generate în timpul rulării aplicaţiilor java, care sunt în general dependente de echipamentele hardware pe care rulează aplicaţiile java. Programatorul nu trebuie să trateze astfel de erori în cadrul unei aplicaţii obişnuite. - clasa Excepţion : modelează excepţii standard ce trebuiesc tratate de către aplicaţiile java. În java tratarea excepţiilor este obligatorie – compilatorul constrânge programatorul să introducă blocuri de tratare a excepţiilor atunci când foloseşte metode care pot arunca aceste excepţii. - Clasa RuntimeException : modelează excepţii ce nu trebuiesc tratate de către programator.

Aruncarea excepţiilor

Pentru a genera sau a arunca o excepţie o metodă trebuie să definiească clauza throws sub forma:

void metoda() throws Eception1, Exception2{
..
if(conditie) throw new Exception1(...);.
...
if(conditie) throw new Exception2(...);
...
return;
}

Generarea şi aruncarea unei excepţii dintr-o metodă se face folosind instrucţiunea throw urmată de excepţia care va fi aruncată.

Tratarea excepţiilor

In momentul eplării unei metode ce conţine o clauză throws, apelul acelei metode trebui inclus în cadrul unui bloc try, urmat de unul sau mai multe blocuri catch responsabile cu tratarea excepţiilor sub forma:

try{
            metoda();
}
catch(Exception1 e1){...}
catch(Exception e2){...}

În momentul în care o excepţie este generată de către o metodă cursul normal de execuţie este întrerup şi se sare la unul dintre blocurile de tratare a excepţiilor. Excepţia este prinsă de acel bloc catch al cărei excepţii asociate se potriveşte cu excepţia aruncă.

Excepţiile sunt prinse în cadrul blocurilor try{…} şi sunt tratate în cadrul blocurilor catch(…).

În cadrul blocurilor pentru tratarea excepţiilor poate fi adăugat opţional şi un bloc finally sub forma:

try{
}
catch(Exception e1){...}
finally{...}

Instrucţiunile din blocul finally sunt executate întotdeauna indiferent de modul de finalizare a instrucţiunilor din blocul try (fie că a fost generată excepţie, fie că nu a fost generată excepţie).

Din cadrul unui bloc catch, o excepţie poate fi aruncată mai departe sub forma:

try{
...
}
catch(Exception e1){ throw e1;}

Crearea propriilor excepţii.

Programatorul are posibilitatea de a defini propriile sale excepţii prin extinderea clasei Exception.

public class TestMyException {
            public static void f() throws MyException {
                  System.out.println("Exceptie in f()");
                  throw new MyException();
            }
            public static void g() throws MyException {
                  System.out.println("Exceptie in g()");
                  throw new MyException("aruncata din g()");
            }
            public static void main(String[] args) {
            try {
                  f();
            } catch(MyException e) {e.printStackTrace();}
            try {
                  g();
            } catch(MyException e) {e.printStackTrace();}
        }
      }
 
class MyException extends Exception {
      public MyException() {}
      public MyException(String msg) {
            super(msg);
      }
}

În continuare este prezentată o aplicaţie ce exemplifică noţiunile prezentate mai sus.

public class CoffeTest {
      public static void main(String[] args) {
            CofeeMaker mk = new CofeeMaker();
            CofeeDrinker d = new CofeeDrinker();
 
            for(int i = 0;i<15;i++){
                  Cofee c = mk.makeCofee();
                  try {
                        d.drinkCofee(c);
                  } catch (TemperatureException e) {
                        System.out.println("Exception:"+e.getMessage()+" temp="+e.getTemp());
                  } catch (ConcentrationException e) {
                        System.out.println("Exception:"+e.getMessage()+" conc="+e.getConc());
                  }
                  finally{
                        System.out.println("Throw the cofee cup.\n");
                  }
            }    
      }
}//.class
 
class CofeeMaker {
      Cofee makeCofee(){
            System.out.println("Make a coffe");
            int t = (int)(Math.random()*100);
            int c = (int)(Math.random()*100);
            Cofee cofee = new Cofee(t,c);
            return cofee;
      }
 
}//.class
 
class Cofee{
      private int temp;
      private int conc;
 
      Cofee(int t,int c){temp = t;conc = c;}
      int getTemp(){return temp;}
      int getConc(){return conc;}
      public String toString(){return "[cofee temperature="+temp+":concentration="+conc+"]";}
}//.class
 
class CofeeDrinker{
      void drinkCofee(Cofee c) throws TemperatureException, ConcentrationException{
            if(c.getTemp()>60)
                  throw new TemperatureException(c.getTemp(),"Cofee is to hot!");
            if(c.getConc()>50)
                  throw new ConcentrationException(c.getConc(),"Cofee concentration to high!");         
            System.out.println("Drink cofee:"+c);
      }
}//.class
 
class TemperatureException extends Exception{
      int t;
      public TemperatureException(int t,String msg) {
            super(msg);
            this.t = t;
      }
 
      int getTemp(){
            return t;
      }
}//.class
 
class ConcentrationException extends Exception{
      int c;
      public ConcentrationException(int c,String msg) {
            super(msg);
            this.c = c;
      }
 
      int getConc(){
            return c;
      }
}//.class

Prinderea tuturor excepţiilor cu un singur bloc catch

Deoarece toate excepţiile au la bază clasa Exception, un bloc try{…} poate fi urmat doar de un singur bloc catch coreszpunzător clasei Exception, care va asigura prinderea tuturor excepţiilor indiferent de tipul lor. Nu se recomandă folosirea acestei metode, şi este bine ca fiecare tip de excepţie să fie tratată în mod individual.

Secvenţa de construire a obiectelor de tip Cofee ar putea fi rescrisă astfel:

try {
      d.drinkCofee(c);
} catch (Exception e) {
      System.out.println("Exception:"+e.getMessage());
}

Excepţii de tip RuntimeException

Excepţiile care sunt construite prin extinderea clasei Exception trebuiesc obligatoriu tratate după cum s-a văzut în secţiunile anterioare. În java există posibilitatea de a construi excepţii pentru care nu trebuiesc construite blocuri de tratare a excepţiilor. Aceste excepţii au la bază clasa RuntimeException.

Excepţiile de tip RuntimeException modelează erori de programare care nu sunt generate de o cauză externă. De exemplu încercarea de apelarea a unei metode din cadrul unui obiect neiniţializat va genera excepţia NullPointerException. Încercarea de accesare a unui element inexistent dintr-un vector va genera excepţia ArrayIndexOutOfBoundException.

String s; s.toString();

Aceste excepţii pot apărea oriunde în program si pot fi extrem de numeroase iar încercarea de “prindere” a lor ar fi extrem de anevoioasa. Din acest motiv compilatorul permite ca aceste excepţii sa rămână ne tratate, tratarea lor ne fiind însă ilegala.