Kivételkezelés problematikája

[Az alábbi idézet forrása: Szlávi Péter – „A Programkészítés didaktikája.”, PhD értekezés, 104-107. o.]

A következő kódrész rávilágít arra, hogy egy kivételkezelési lehetőségeket nem tartalmazó nyelvben (mint a Pascal) hogyan lehetne következetesen végigvinni a kivételkezelést:

A

{Hibakezelés inic:}
hibaKod:=OK;

B

fN:='KODOL.BE';
If not OlvasasraNyit(f,fN) then hibakod:=Hiba_NemLetezoFile;

C

If hibaKod=OK then
{$i-}
Begin
  Readln(f,N);
  If (IOResult<>OK) or
     not ((N>=1) and (N<=MaxN)) {Ef(N)} then

  Begin
    hibaKod:=HIBA_FeltetelSertes
  End
    else
  Begin

D

    For i:=1 to N do
    Begin
      If hibaKod=OK then
      Begin
        Readln(f,adat[i]);
        If IOResult<>OK then hibaKod:=Hiba_FileOlvasas;
      End; {If hibaKod}
    End; {For i}
  End; {If (IOResult}
End; {If hibaKod}

E

If hibaKod<>Hiba_NemLetezoFile then Close(f);
{$i+}

F

{Hibakezelö "farok":}
Case hibaKod of
   Hiba_NemLetezoFile :
     Begin
       HibaKezeles('A keresett file nem található:'+fN+'.',
                   99{megállási kód},True{megáll});
      End;
   HIBA_FeltetelSertes :
      Begin
        HibaKezeles('A file adata hibás:'+fN+'.',
                    99{megállási kód},True{megáll});
      End;
   HIBA_FileOlvasas :
      Begin
        HibaKezeles('A file olvasási hiba:'+fN+'.',
                    99{megállási kód},True{megáll});
      End;
 End; {Case hibaKod}

Az A-val jelölt részben a hiba bekövetkezésének (és milyenségének) rögzítését végző hibaKod változó alaphelyzetbe hozása történik.

A B rész az ellenőrzött megnyitást vég­zi; s hiba esetén egy saját hibakód kerül följegyzésre.

A C résszel kezdetét veszi a tényle­ges adatbeolvasás (persze, ha a megnyitás sikeres volt). Elsőként az adatok mennyiségét meghatá­rozó számadat került beolvasásra, amellyel szemben elvárásokat fogalmaztunk meg. Az olvasás fizikai kivitelezhetőségének és a lo­gikai elvárás ellenőrzése után következik a D részbeli „tömeg-adat” beolvasása. A C részben ez esetben nem különböztetjük meg a logi­kai és a fizikai hibát.

A D részben érzékelem akár a fájlon túli, akár a fizikai hibát. Most nincsen semmi logikai feltétel az adatelemekkel szemben. Vegyük észre, hogy a D-beli ciklus akkor is végig lefut, ha hiba következett be. Természetesen a For ciklus While-lal helyettesítésével a fölösleges végrehajtás megszüntethető lenne, de fontosabbnak tartot­tam a tervezési logikát követni, mint a kivételkezelés miatt azt módosítani. Ha tetszik: a végre­haj­tási logikát a hibakezelés miatt csak a minimálisan szükséges mértékben módosítottam.

Az E rész­ben a fájl lezárására kerül sor. Az F a hibakezelő farok, amely feladata a hiba esetleges bekövetke­zésekor elvégzendő tevékenységek megszervezése.

Összefoglalásul két dolog kiemelendő.

1.      A kivételkezelés nélküli nyelvekben ilyen funkciók beleerőltetése a programba –sajná­latos mó­don– csak a program logikáját is érintően lehetséges. Ennek során nyert kód­ban roppant nehéz felfedezni a lényegi (tervezéskor kapott) szerkezetet. Így az esetle­ges hibakeresés a szokásos­nál is körülményesebbé válik.

2.      Ha szükséges a kivételkezelés megvalósítása, akkor nagyjából a következő módon vé­gezhető el:

a.       alprogramonként célszerű egy, csak a hibakódot raktározó változót deklarálni (el­kerülen­dő az esetleges interferencia);

b.      ezt a változót az alprogram elején hibátlanságot jelző állapotba kell hozni;

c.       minden olyan helyen, ahol hiba következhet be ellenőrizni kell, s a további kód­rész egy hiba­vizsgálattól függő elágazásba kerül (itt bonyolódik a struktúra);

d.      az alprogram egy „farokrésszel” zárul, amelyben az elkövethető hibák szerinti kap­csoló­ban az ilyenkor elvégzendő tevékenységeket hajtjuk végre.

Egy gondolat a d. ponthoz: mivel e tevékenységek egy része (talán nagy része) „sablonos” tevé­kenységeket jelent, célszerű ezekhez előre elkészíteni egy vagy több eljárást. A fenti példában a Hibakezelés eljárás ilyen univerzális alprogram:

Procedure HibaKezeles(s:String; kod:Byte; megall:Boolean);
Begin
  Writeln(s);
  If megall then
  Begin
    Halt(kod);
  End; {If megall}
  ReadKey
End; {HibaKezeles}

Feladata: egy paraméterként megadott szöveg megjelenítése a képernyőn, és vagy megállni egy pa­raméterben szabályozott kóddal –ha lehetetlen a futás folytatása–, vagy visszatérni.

A kódba bekerült fájlnyitó és hibakezelő eljárások –és velük kapcsolatos fogalmak– önálló prog­ramfájlban elkülöníthetők, és igény szerint bármikor –újra megírás nélkül– beépíthető a kódba.