A J# programozási nyelv

Kivételkezelés



Kivételek definiálása

Mivel minden végrehajtható kódrészlet, amely potenciálisan kivételt okozhat valamely osztály valamely metódusában van elhelyezve, ezért a keletkezhető kivételeket a függvények deklarációjánál kell megadni. Ennek szintaxisát tehát a függvény szintaxisának része:

    láthatóság módosítók 
    visszatérési_típus függvénynév(típus paraméternév (, típus paraméternév)*) 
    [throw kivétel_típus (, kivétel_típus)*]
    [ { 
        utasítások
        return kifejezés;
    } ]
(bővebben lásd az Alprogramok, modulok c. fejezetet)

Kivételek kiváltása

Amikor olyan pontohz érünk a programban, amikor valamilyen kivételes esemény történt, és mi nem tudjuk ezt lekezelni, ill. ezt a külvilág felé egyéb módon korrekten jelezni, akkor dobhatunk kivételt. Ezt a throw kulcsóval tehetjük meg, ami a mögé írt kifejezés értékét fogja kivételként eldobni.

public void methodWithNullReference() throw java.lang.NullPointerException { ... throw new java.lang.NullPointerException; ... }

Kivételek kezelése

Ha valamely kódrészlet kivételt dobhat, és mi erre fel szeretnénk készülni, akkor az adott kódrészletet egy úgynevezett try-catch-finally szrkezetbe tehetjük, ami révén ha kivétel váltódik ki, azt mi elkaphatjuk, és ha tudjuk, megfelelően le is kezelhetjük a kivételes eseményt.

Szintaxisa:

    try { ... }
    catch(kivétel_típus paraméter) { ... }
    ...
    catch(kivétel_típus paraméter) { ... }
    finally { ... }    
Ha a kivétel a catch ágban megadott típusú, akkor az az ág fog végrehalytódni. Csak egy ág hajtódik végre, és a típus vizsgálata fentről lefelé történik. Legvégül a finally ág mindig lefut, még akkor is, ha nem volt kiválasztható catch ág.

Kivételek terjedése

A kivétel a a hívási láncon visszafelé terjed, egészen addig, amíg valahol le el nem kapják. Ha egy kivételt egy catch ágban elkapunk, akkor a kivétel terjedése megáll. Amennyiben nem tudjuk teljesen lekezelni a kivételes eseményt, akkor továbbdobhatjuk az elkepott kivételt egy paraméter nélköli throw; utasítással. (A paraméter nélköli throw; utasítás csak catch ágban használható.) Vagy akár egy teljesen más kivételt dobhatunk helyette.

Kétféle kivételek

A J# két típusú hibaüzentet generál: Java-s és .Net-s kivételeket.

Nagyon sok Java-s futási idejű kivétel sematikusan megegyezik a .Net Framework-ben; például a java.lang.NullPointerException hasonló a NullReferenceException-höz. Amikor elkapunk egy Java-s futási idejű kivételt a forráskódban, a J# fordító gondoskodik arról, hogy az eredményként kapott futtatható kód elkapja a kivétel .NET Framework-beli megfelelőjét.

try { methodWithNullReference(); } catch (java.lang.NullPointerException e) { // Elkapja mind a java.lang.NullPointerException-t // és a System.NullReferenceException-t. e.printStackTrace(); }

Két lehetőség van null-referencia kivétel létrehozására az előző példában: A catch (java.lang.NullPointerException e) blokk elkapja mind a NullPointerException-t, mind a NullReferenceException-t.

Lehetőségünk van, hogy főleg Java-specifikus kivételeket használjunk, és általában mellőzzük azokat a .NET-es kivételeket amelyeknek van Java-s megfelelőjük.

Változások a kivételek leképezésében

A J# 2005 hozott néhány változást ezen a téren. Régebben nem tartalmazhatott egy catch all exceptions-t egy egyszerű catch szakasz, ami normális esetben lehetséges a Java-ban egy java.lang.Throwable elkapásával. A .NET Framework előző verzóiban nem volt lehetséges elkapni egy ilyen java.lang.Throwable-t, de a változtatások a fordítóban már lehetővé teszik ezt egy szimpla catch szakaszban. Szintén lehetséges .NET-es kivételeket elkapni egy tagolt catch szakaszban.

A következő példák bemutatják a kivételkezelés különféle módjait, és a hozáájuk tartozó viselkedéseket.

// Példa 1: Throwable elkapja az összes kivételt. try { // ... } catch (Throwable t) { // ... }

try { // ... } catch (System.Exception ex) { // Az eredeti futási idejű szűrőt áthelyezzük ebbe a szakszba Throwable t = Throwable.wrapException(ex); if (t == null) rethrow; // ... } catch (Throwable t) { // ... }

// Example 2: Explicit kapunk el .NET Framework exception-öket amíg működik try { // ... } catch (Throwable t) { System.out.println(t.get_InnerException().get_StackTrace()); } catch (System.Exception except) { // ... }

Az előző példában a java.lang.Throwable csak Java-s kivételeket kap el, többit pedig explicit módon kapjuk el.

// Example 3: Elkap unmapped .NET exception alosztályt
try { // ... } catch (Throwable t) { // ... } catch (ExceptionUnmapped except) { // ... }

Ennél a pédánál minden kivételt az ExceptionUnmapped fog elkapni, nem a java.lang.Throwable.

A következő példában minden kivételt a megfelelő helyen kezelünk.

try { // ... } catch (ExceptionUnmapped except) { // ... } catch (System.Exception ex) { // A catch ágak sorrendjének megváltoztatása kettős viselkedést vált ki. Throwable t = Throwable.wrapException(ex); if (t == null) { rethrow; } } catch (Throwable t) { // ... }