Exceptii
In limbajul Java exceptiile ofera un mecanism eficient de identificare si rezolvare a erorilor. Exceptiile reprezinta situatii care apar in timpul executiei unui program si care determina oprirea acestuia. Java ofera posibilitatea tratarii exceptiilor prin stabilirea unei cai alternative de continuare a executiei programului.
De exemplu, pot fi generate exceptii in urmatoarele cazuri:
• realizarea unei impartiri la zero ArithmeticException;
• deschiderea unui fisier care nu exista FileNotFoundException;
• accesarea indexului unui tablou care depaseste limitele IndexOutOfBoundsException;
• utilizarea unui atribut care nu a fost definit NoSuchFieldException.
package ro.virtualcampus.exceptie; | |
public class Exceptie { | |
public static void main(String[] args) { | |
int a = 257; | |
System.out.println("Rezultatul impartirii lui " + a + " la 0 este " + a / 0); | |
} | |
} |
Daca este executata aplicatia Exceptie.java, se poate observa mesajul de eroare care este generat la realizarea unei impartiri la 0.
Exception in thread "main" java.lang.ArithmeticException: / by zero at ro.virtualcampus.exceptii.Exceptie.main(Exceptie.java:7)
In contextul discutiilor despre exceptii putem intalni doua situatii:
• generarea de exceptii folosind instructiunea throw;
• tratarea exceptiilor utilizand constructii de genul try … catch.
Generarea exceptiilor
La aparitia unei exceptii este generat automat un obiect care contine toata informatia corespunzatoare exceptiei. Generarea unei exceptii poate fi realizata prin intermediul instructiunii throw, astfel:
throw obiect_exceptie;
Putem considera ca exceptiile reprezinta al doilea tip returnat de catre o metoda. Din acest motiv, o metoda trebuie sa declare tipurile de exceptii care pot fi lansate din interiorul ei. In caz contrar, compilatorul Java genereaza o eroare de compilare.
Declararea tipurilor de exceptii care pot aparea intr-o metoda este realizata folosind cuvantul cheie throws in declaratia metodei.
[modificatori] tip_metoda nume_metoda( [lista parametrii] ) [throws tip_exceptie1, ... ] { // corp metoda }
Exceptiile declarate in antetul unei metode extind clasa Exception si cuprind conditii de eroare care apar datorita problemelor de comunicatie cu sisteme externe sau datorita lucrului cu intrarile. Aceste conditii de eroare trebuie tratate dinamic, deoarece ele nu pot fi prevenite.
Nu toate tipurile de exceptii trebuie declarate folosind clauza throws. Astfel de exceptii extind clasa RuntimeException si au ca si cauza greselile de programare.
package ro.virtualcampus.exceptii; | |
public class Exceptie2 { | |
public static void main(String[] args) throws IndexOutOfBoundsException { | |
int tablou[] = { 2, 4, 5, 1 }; | |
int index = 5; | |
if (index >= tablou.length || index < 0) | |
throw new ArrayIndexOutOfBoundsException(); | |
else | |
System.out.println("elementul tablou[" + index + "] este " + tablou[index]); | |
} | |
} |
Clasa Exceptie2 permite testarea valorilor pentru indecsii unui tablou. Daca indexul corespunzator unui element al tabloului depaseste marginile acestuia, atunci este generata (aruncata) o exceptie de tipul IndexOutOfBoundsException.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at ro.virtualcampus.exceptii.Exceptie2.main(Exceptie2.java:9)
In cazul in care indexul verificat respecta dimensiunea tabloului, este afisat elementul corespunzator acestui index. In acest caz nu este obligatorie semnarea metodei main() cu tipul exceptiei lansate, deoarece exceptia este de tipul eroare logica a programului (RuntimeException).
In mod normal nu este indicata captarea si tratarea acestor exceptii, ci corectarea lor.
package ro.virtualcampus.exceptii; | |
public class Exceptie2 { | |
public static void main(String[] args) { | |
int tablou[] = { 2, 4, 5, 1 }; | |
int index = 3; | |
if (index >= tablou.length || index < 0) | |
System.out.println("indexul [" + index + "] depaseste marginile tabloului"); | |
else | |
System.out.println("elementul tablou[" + index + "] este " + tablou[index]); | |
} | |
} |
Categorii de exceptii
Limbajul Java defineste o ierarhie de clase pentru tratarea exceptiilor pornind de la clasa Throwable, care contine doua clase: Error si Exception. Obiectele de tipul Error sunt generate de catre mediul de dezvoltare Java si nu pot fi preluate in vederea tratarii.
O subclasa importanta a clasei Exception este RuntimeException. Aceasta clasa defineste exceptiile care pot fi evitate de catre programator, printr-o mai buna organizare a surselor (erori logice). La parcurgerea unui tablou poate fi generata o exceptie de tipul RuntimeException (ArrayIndexOutOfBoundsException), daca indexul tabloului respectiv este depasit. Aceasta exceptie poate fi preintampinata daca utilizatorul ia in calcul limitele tabloului.
De asemenea, in superclasa Exception poate fi intalnita o alta categorie importanta de exceptii, si anume IOException. Clasa IOException contine exceptiile care apar in contextul lucrului cu intrari/iesiri. Accesarea unui fisier care nu exista va determina generarea unei exceptii de tipul IOException, FileNotFoundException.
Throwable Error AssertionError LinkageError BootstrapMethodError ClassCircularityError ClassFormatError UnsupportedClassVersionError ExceptionInInitializerError IncompatibleClassChangeError AbstractMethodError IllegalAccessError InstantiationError NoSuchFieldError NoSuchMethodError NoClassDefFoundError UnsatisfiedLinkError VerifyError ThreadDeath VirtualMachineError InternalError OutOfMemoryError StackOverflowError UnknownError Exception ClassNotFoundException CloneNotSupportedException InterruptedException IOException EOFException FileNotFoundException InterruptedIOException MalformedURLException ProtocolException SocketException ConnectException UnknownHostException UnkbownServiceException ReflectiveOperationException ClassNotFoundException IllegalAccessException InstantiationException InvocationTargetException NoSuchFieldException NoSuchMethodException RuntimeException ArithmeticException ArrayStoreException ClassCastException ConcurrentModificationException EnumConstantNotPresentException IllegalArgumentException IllegalThreadStateException NumberFormatException IllegalMonitorStateException IllegalStateException IndexOutOfBoundsException ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException NegativeArraySizeException NullPointerException SecurityException TypeNotPresentException UnsupportedOperationException
Tratarea exceptiilor
Java ofera o solutie eficienta de rezolvare a exceptiilor care apar intr-un program prin intermediul mecanismului de tratare a exceptiilor. Implementarea unei astfel de solutii se face folosind constructii de genul try … catch … finally.
Sintaxa generala pentru o instructiune try … catch … finally este urmatoarea:
try { // instructiuni supravegheate } catch (Exceptie1 e1) { // tratare exceptie e1 de tip Exceptie1 } catch (Exceptie2 e2) { // tratare exceptie e2 de tip Exceptie2 } finally { // instructiuni care se executa neconditionat }
Blocul try este utilizat pentru a delimita instructiunile care vor fi urmarite in vederea identificarii exceptiilor. Daca este lansata o exceptie, se suspenda executia restului de instructiuni din blocul try si sunt verificate blocurile catch. Exceptia este tratata de primul bloc catch care contine tipul exceptiei sau un supertip al acesteia.
In cazul in care exceptia nu este tratata de niciun bloc catch, ea va fi returnata in metoda apelanta. Netratarea exceptiei si returnarea ei pana in varful ierarhiei va determina in cele din urma oprirea programului si afisarea unui mesaj corespunzator.
package ro.virtualcampus.exceptii; | |
public class TratareExceptii { | |
public static void main(String[] args) { | |
int nr = 0; | |
try { | |
nr = Integer.parseInt(args[0]); | |
} catch (NumberFormatException e) { | |
System.out.println("NumberFormatException"); | |
nr = 1; | |
} catch (ArrayIndexOutOfBoundsException e) { | |
System.out.println("ArrayIndexOutOfBoundsException"); | |
nr = 2; | |
} finally { | |
nr++; | |
} | |
System.out.println("nr = " + nr); | |
} | |
} |
In clasa TratareExceptii poate fi observata o modalitate de tratare a exceptiilor care sunt generate ca urmare a validarii valorii atribuite elementului corespunzator indexului 0 al listei de parametri, args[]. Daca este omisa introducerea unei valori pentru parametrul args[0] in linia de comanda, se va genera o exceptie de tipul ArrayIndexOutOfBounds. Daca valoarea atribuita parametrului args[0] nu poate fi convertita la tipul intreg, se genereaza o exceptie de tipul NumberFormatException. Se poate observa ca instructiunea din interiorul blocului finally este executata intotdeauna.
Definirea de exceptii utilizator
Limbajul Java ofera posibilitatea definirii propriilor exceptii, pentru a pune in evidenta conditii de eroare care nu au fost prevazute in ierarhia exceptiilor standard. O clasa de exceptii nou creata trebuie sa extinda unul din tipurile existente de exceptii. Extinderea se realizeaza dintr-o clasa a carei semnificatie este asemanatoare clasei Exception.
package ro.virtualcampus.app; | |
import java.io.*; | |
import ro.virtualcampus.bank.Cont; | |
import ro.virtualcampus.bank.FonduriInsuficiente; | |
public class Banca { | |
static BufferedReader fin = new BufferedReader(new InputStreamReader(System.in)); | |
public static boolean valid(char optiune) { | |
char[] optiuni = { 'd', 'r', 's', 'i' }; | |
for (int i = 0; i < optiuni.length; i++) { | |
if (optiune == optiuni[i]) | |
return true; | |
} | |
return false; | |
} | |
public static void main(String args[]) { | |
Cont c = new Cont("RO12SV00009999124"); | |
char optiune; | |
do { | |
System.out.println("{ d - depunere, r - retragere, s - sold, i - iesire }"); | |
optiune = 's'; | |
try { | |
optiune = fin.readLine().charAt(0); | |
switch (optiune) { | |
case 'd': | |
System.out.println("Suma depusa: "); | |
c.depune(Double.valueOf(fin.readLine())); | |
break; | |
case 'r': | |
System.out.println("Suma retrasa: "); | |
c.retrage(Double.valueOf(fin.readLine())); | |
break; | |
case 's': | |
System.out.println("Sold disponibil: " + c.getSold()); | |
break; | |
} | |
} catch (FonduriInsuficiente e) { | |
System.out.println("fonduri insuficiente"); | |
System.out.println("necesar: " + e.getSuma()); | |
} catch (IOException e) { | |
System.out.println("eroare citire \n"); | |
} catch (NumberFormatException e) { | |
System.out.println("valoare gresita \n"); | |
} | |
} while (valid(optiune) && optiune != 'i'); | |
} | |
} |
Aplicatia de mai sus cuprinde clasele: Cont, FonduriInsuficiente, Banca. Aceste clase sunt necesare pentru a gestiona situatiile care apar intr-o banca in ceea ce priveste tranzactiile care pot fi realizate la nivelul unui cont.
Cazurile exceptionale sunt definite prin intermediul clasei FonduriInsuficiente, care extinde clasa Exception. Exceptii de tipul FonduriInsuficiente sunt generate in metoda retrage() din clasa Cont la incercarea de retragerea a unei sume care depaseste soldul contului. Tratarea exceptiilor generate se realizeaza folosind o constructie try … catch, in metoda principala a clasei Banca.
{ d - depunere, r - retragere, s - sold, i - iesire } d Suma depusa: 120.0 { d - depunere, r - retragere, s - sold, i - iesire } r Suma retrasa: 230.0 fonduri insuficiente necesar: 110.0 { d - depunere, r - retragere, s - sold, i - iesire } s Sold disponibil: 120.0 { d - depunere, r - retragere, s - sold, i - iesire }