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);
}
}
Exerciţiu: Testaţi aplicaţia de mai sus.
Adăugaţi o nouă clasă de tip excepţie şi
testaţi folosirea acesteia.
Ī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
Exerciţiu: Construiţi un proiect Eclipse şi
adăugaţi īn cadrul acestuia aplicaţia de mai sus. Testaţi
aplicaţia.
Exerciţiu: Īn varianta curentă clasa CofeeMaker
este astfel construită īncāt permite generarea unui numar infinit de
obiecte de tip Cofee. Modificaţi aplicaţia astfel īncāt un CofeeMaker
să permită crearea unui număr limitat de obiecte de tip Cofee,
şi īn momentul īn care acest număr limită a fost atins, metoda
makeCofee() să returneze o excepţie specifică.
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.
Exerciţiu: Studiaţi articolul Exception-Handling
Antipatterns.