A Dylan programozási nyelv

Kivételkezelés



Kivételkezelés


A kivétel (condition) egy objektum amely információt szolgáltat a kivételkezelőnek (handler). Egy kivétel objektum olyan szituációt reprezentál amit kezelni szükséges. Ilyen lehet például valamilyen hiba, figyelmeztetés, vagy egy hiba utáni helyreállítás.
Az összes kivétel a condition osztály példánya. Ennek az osztálynak számos alosztálya van a különböző hibák kezelésére.

Handler - a kivételkezelő függvény

A kivételkezelő egy függvény, melynek feladata valamilyen tipusú kivétel kezelése. A kivételkezelők dinamikusan installálhatók a let handler lokális deklarációval, vagy pedig a blokk utasítás exception részében (lásd következő pont). A dinamikusan installált kivételkezelők a törzs futása alatt aktívak. A korábban installált kivételkezelők magasabb precedenciával rendelkeznek a később installáltaknál. Ha nincs dinamikusan installált kivételkezelő, akkor a default-handler hívódik meg.
Azt a mehanizmust, amely megkeresi a legkorábban installált kivételkezelőt egy kivételhez, jelzésnek (signaling) nevezzük. A jelzés a signal függvény hívásával történik (java-ban ennek felel meg a throw). Ha egy kivétel jelzése megtörtént, akkor a kivételkezelő rendszer megkeresi hozzá a (legkorábban installált) alkalmazható kivételkezelőt. Egy kivételkezelő alkalmazható ha olyan tipusú kivételt kezel amelynek a kiváltott kivétel példánya.

Mint az összes többi függvény, a kivételkezelő is visszatérhet valamilyen értékkel. A kivételkezelésnek kétféle módja van: a helyreállítás és a kilépés. A helyreállítás azt jelenti, hogy néhány helyreállító művelet végrehajtása után visszatérünk a jelzo egységhez és folytatjuk a végrehajtást. A kilépés hatására a vezérlés a jelzo egységen kivülre kerül. Nézzünk most három különbözo példát a kivételkezelésre:
A példákban fájlokat fogunk másolni, de előfordulhat, hogy a fájlok másolásvédettek. Ennek kezelésére először létrehozzuk a másolásvédelem kivételosztályát.

// Már létezik egy elöre definiált osztály a fájlrendszerben bekövetkezett hibákhoz // Mi most ennek egy alosztályát hozzuk létre define class () slot file, init-keyword: file:; // Itt tároljuk a file nevét end class;

Most pedig létrehozzuk a fájlmásoló metódust amelyik jelezni fogja az előzőleg elkészített kivételt, amennyiben a másolandó fájl másolásvédett.

define method copy-file (source, destination) if (copy-protected?(source) ) signal(make(, file: source)); else // ide kerülhet a másolás kódja notify-user("Copying %s to %s.", source, destination); end if; end method;

A következő példában fájlok sorozatát fogjuk átmásolni. Ha valamelyik fájl másolásvédett, akkor erről értesítést adunk. A hátralévő fájlok másolásra kerülnek. Ez a példa a helyreállító kivételkezelést mutatja be.

define method backup-all-possible (volume, archive) // deklarálunk egy kivételkezelőt let handler = method(condition, next) // A kivételkezelőértesiti a felhasználót aztán minden folytatódik notify-user("The file %s could not be copied.", condition.file); end method; // elkezdjük másolni a fájlokat. // a kivételkezelőitt már érvényben van for (each-file in volume) copy-file(each-file, archive) end for; end method;

A következő példában ha másolásvédett fájlhoz érkezünk akkor befejezzük a másolást. A hátralévő fájlok nem kerülnek másolásra.

define method backup-exit (volume, archive) // készintünk egy blokkot amiből kiléphetünk block(exit) let handler = method(condition, next) // értesitjük a felhasználót és kilépünk notify-user("Backup interrupted: the file %s could not be copied.", condition.file); exit(#f); end method; // elkezdjük a másolást, a kivételkezelőérvényben van for (each-file in volume) copy-file(each-file, archive) end for; end block; end method;

Exception záradék


Az exception záradék a handler függvényhez hasonlóan bizonyos típúsú kivételek kezelését teszi lehetővé. Itt azonban egyszerre több kivételosztályhoz is megadhatunk kezelő részt. Az itt definiált kivételkezekő "függvények" a handler-hez hasonóan precedenciával rendelkeznek. A kivétel kiváltásához legközelebb definiált résznek lesz legelőször lehetősége a kivétel lekezelésére. Ha nem adunk meg exception záradékot, akkor szintén a default-handler fogja a kivételt kezelni.

A következő példának ugyanaz a hatása mint a handler függvény 2. példájában megadott backup-exit metódusnak. Itt viszont a blokk utasítás exception részét használjuk kivételkezelésre.

define method backup-block(volume, archive) // készen állunk a másolásra block() // elkezdjük a másolást for (each-file in volume) copy-file(each-file,archive) end for; exception (condition :: ) notify-user("Backup interrupted:the file %s could not be copied.", condition.file); end block; end method;

Cleanup záradék


Sok program számára szükséges a lekötött erőforrások felszabadítása vagy valami más hasonlóan fontos munka mindenképpeni elvégzése, amikor egy blokkot elhagy. Legyen ez tervezett vagy nem tervezett elhagyás. A blokkoknál lehetőségünk van megadni egy opcionális cleanup záradékot, ami nem változtatva meg a blokk visszatérési értékét, és mindig végre lesz hajtva.

let fd = open-input-file(); block (return) let (errorcode, data) = read-data(fd); if (errorcode) return(errorcode); end if; process-data(data); cleanup close(fd); end;