Gyakorlati alapok II.

Kivételfajták

 

Amint az az egyik előző, a Try-catch-finally blokkok című fejezetből kiderült, a kivétel (exception) egy olyan, sokféle formában megmutatkozó problémacsomag, amely valamilyen módon megakaszthatja a Java-program futását. A Java-nyelv lehetőséget ad arra, hogy védekezzünk ellenük, sőt ha előre látjuk a probléma felmerültét, akkor kísérletet tehetünk megszüntetésére is.

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

A kivételek 3 nagy csoportba osztályozhatók:

  1. ellenőrzött kivételek (checked exceptions)

  2. nem ellenőrzött kivételek (unchecked exceptions)

  3. hibák (errors)

Ellenőrzött kivételek

 

Az ellenőrzött kivételek attól ellenőrzöttek, hogy előre láthatjuk a felmerülő problémát és kísérletet tehetünk megszüntetésükre. Tipikusan ilyen kivétel a Try-catch-finally blokkok című fejezet egyik példakódjában felhasznált FileNotFoundException kivétel. Egy fájl közeli vagy távoli elérése és megnyitása ugyanis nagyon sokféle hardver-, és szoftverkomponens egyidejű sikerességén múlik, más szóval igen kényes művelet. Sokkal problémásabb, mint mondjuk 2 db integer összeadása. A Java alkotói úgy döntöttek: a nagy hibalehetőségű műveleteknél a legkényesebbeket egyenesen kötelező lekezelni, azaz kötelező try-catch blokk közé illeszteni, nélküle fordítási hibát kapunk. Ez a szigor persze a programfutás előnyére válik, hiszen a kötelező hibakezeléssel jóval biztonságosabban futó kód állítható elő.

 

Gyakori ellenőrzött kivételek:

Nem ellenőrzött kivételek

 

Sajnos nem tudunk minden problémát előre látni, sok magán a programozó tudásán, figyelmén múlik. Minden programozó találkozott már NullPointerException vagy ArrayIndexOutOfBoundsException nevű kivétellel; a magam részéről az utóbbit tanulmányaim során sokszor elkövettem. A programozási hiba legtöbbször futási idő alatt derül ki és sok esetben nem is számítunk rá, ezért a nem ellenőrzött kivételeket nevezik futásidejű kivételeknek is (runtime exceptions). Az alábbi Java-kódban egy ízléses ArrayIndexOutOfBoundsException kivételt generálunk, hiszen a for ciklus során szándékosan túllépjük a fix méretű tömb határát:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {
    public static void main(String[] args) {
        int[] tomb = new int[5];
        for(int i = 0; i < 6; i++){
            System.out.print(tomb[i] + " ");
        }
    }
}

Végeredmény:

0 0 0 0 0 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Main.main(Main.java:5)

 

Gyakori nem ellenőrzött (futásidejű) kivételek:

Hibák

 

Az error mindig komolyabb, általában vagy hardver, vagy mélyebb, rendszerszintű (minimum a JVM-től induló) hibát jelent.

 

A hibajellegek szétválasztása osztályszinten is megtörténik: csak elég egy gyors pillantást vetnünk az Exception ősosztálya, a java.lang.Throwable (nem teljesen mutatott) osztályhierarchiájára...

 

www.informatika-programozas.hu

Forrás - Source: proofbyexample.com

 

...amelyben az Error és Exception külön ágakat képvisel.

 

Az alábbi "futtatható" Java-kód verem-túlcsordulást fog okozni (StackOverflowError). A verem (stack) egy speciális, LIFO-működésű (Last In First Out) memóriaterület, amelyben a regiszterek tartalmát utolsó-betesz-első-kivesz elven ideiglenesen tárolhatjuk. A hiba produkálása úgy történik, hogy egy saját metódust (metodus()) önmagában, azaz saját metódustörzsén belül folyamatosan meghívunk (úgy mondjuk: rekurzív módon. Ez tehát tipikusan a saját farkába harapó kígyó, az Uroboros példája.) A keletkezett hiba már nem is exception, hanem error jellegű, azaz már komolyabb hardverhiba, hiszen teljesen feltöltöttük, ezáltal pedig használhatatlanná tettük a verem-memóriaterületet.

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {


public static void metodus() {
    System.out.println("Metódus");
    metodus();
    }
 

public static void main(String args[]) {
    metodus();
    }
}

 

Végeredmény:

Metódus

Metódus

Metódus

...

at Main.metodus(Main.java:5)

at Main.metodus(Main.java:5)

at Main.metodus(Main.java:5)

...

 

A fenti osztályhierarchiából kiderül, hogy az error hibát nem tudjuk elkapni az Exception e használatával (azaz a catch ág soha nem fut le):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {


public static void metodus() {
    System.out.println("Metódus");
    metodus();
    }
 

public static void main(String args[]) {
    try{
        metodus();
    }
    catch (Exception e){
        System.out.println("\nVerem-túlcsordulás!");
    }
}

 

Végeredmény:

Metódus

Metódus

Metódus

...

at Main.metodus(Main.java:5)

at Main.metodus(Main.java:5)

at Main.metodus(Main.java:5)

...

 

Ellenben Error e (vagy StackOverflowError sofe) definiálásával elkaphatjuk a keletkezett hardverhibát:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {


public static void metodus() {
    System.out.println("Metódus");
    metodus();
    }
 

public static void main(String args[]) {
    try{
        metodus();
    }
    catch (Error e){
        System.out.println("\nVerem-túlcsordulás!");
    }
}

 

Végeredmény:

Metódus

Metódus

Metódus

...

Verem-túlcsordulás!

 

Végezetül vizsgáljuk meg a fenti kód apró módosítását, amely során a finally blokkot is implementáljuk. A kódból kivesszük a rekurziót, helyette a különálló metódusban szabályozott for ciklust használunk a "Metódus" szöveg kiírására:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {

public static void metodus() {
    for(int i = 0; i <= 5; i++){
        System.out.println("Metódus");
        }
    }

public static void main(String args[]) {
    try{
        metodus();
    }
    catch (StackOverflowError sofe){
        System.out.println("\nVerem-túlcsordulás!");
        System.exit(0);
    }
    finally{
        System.out.println("\nNem keletkezett verem-túlcsordulás!");
        }
    }
}

 

Végeredmény:

Metódus
Metódus
Metódus
Metódus
Metódus
Metódus

Nem keletkezett verem-túlcsordulás!

 

Bár a fenti, error jellegű kivételt lekezeltük, sok programozó mégis azt javasolja, hogy az ilyen jellegű hibákat inkább ne kezeljük le, hanem hagyjuk a JVM-re. Érvelésük meggyőző, hiszen például egy OutOfMemoryError hiba azt jelzi, hogy elfogyott a memória, ami elég durva hardver-probléma és amelyet úgysem lehet megoldani alkalmazásszintű programozáskor.

 

Gyakori error-jellegű hibák: