kivetelkez_phd_isk

Download Report

Transcript kivetelkez_phd_isk

KIVÉTELKEZELÉS
Programozási nyelvek
összehasonlító elemzése
Készítette: Pásztor Attila
KF GAMF
ELTE-IK DOKTORI ISKOLA
PHD hallgató
1
KIVÉTELKEZELÉS
Tartalom:

Kivételkezelés, kivétel fogalmai

Kezeletlen kivétel

”Kivételkezelés” a C nyelvben

A kivételkezelés kezdetei :
FORTRAN, COBOL, PL/I

Fejlett kivételkezelés :C++, JAVA, C#

Kivételkezelés adatbáziskezelő nyelvekben :
TSQL, PLSQL, FOXPRO

Egyebek

Összefoglalás
2
Elvárás: az előllított program
helyesen és megbízhatóan
működjön
Alapvető elvárás:
 helyes - a specifikációnak
megfelelően működik

robosztus – semmilyen körülmények
között sem okozzon nem várt
mellékhatást, katasztrófát
3
Kezeletlen kivétel
class Program
{
static void Main(string[] args)
{
int a = Beolvas("z els");
int b = Beolvas(" második");
int c = a + b;
Console.WriteLine("A két szám összege: {0}", c);
}
static int Beolvas(string Aktuális)
{
Console.Write("A"+Aktuális+" szám: ");
string s = System.Console.ReadLine();
int a = int.Parse(s);
return a;
}
}
4
Kivétel : olyan futás közben fellépő hiba ami
megszakítja az utasítások normál futási sorrendjét
A programok futása közben hibák léphetnek fel.
 Szoftverhibák
– a futtatott programban,






kísérlet zérus osztásra
null pointer értékre való hivatkozás
aritmetikai túlcsordulás, alulcsordulás
tömb hibás indexelése
hibás típus konverzió kísérlete
hibás input stb.
– az operációs rendszerben
meglévő programozói hibák.

Hardverhibák
– elromlott winchester miatti leállások,
– elfogy a memória, stb.
5
Kivételkezelés feladata :
- olyan események kezelése melyek nehézzé, vagy
lehetetlenné teszik a program normál módú folytatását
- a futási hibák kijavítása (ha lehetséges), vagy a program
leállítása úgy, hogy a legkisebb hibák keletkezzenek
Kivételkezelés régen :
- abortált a program :-(
- minden alprogram valamilyen jelzést (hibaértéket)
ad vissza, hogy a lefutás OK., vagy nem:
6
”Kivételkezelés”
a
C
nyelvben
int FGV()
{
FILE *ifptr=NULL;
FILE *ofptr=NULL;
char *bet=NULL;
bet=calloc(1,1);
ifptr=fopen("C:\\szöveg.txt","r");
ofptr=fopen("C:\\uj.txt","w");
do{
*bet=getc(ifptr);
putc(*bet,ofptr);
}while(!feof(ifptr));
fclose(ifptr);
fclose(ofptr);
free(bet);
return 0;
}
Nem megbízható
program !
Megoldások: 1-hibakezelés helyben a „veszélyes”
helyeken
2- közös hibakezelő rész
7
”Kivételkezelés” a C nyelvben
- hibakezelés helyben
int FGV()
{
FILE *ifptr=NULL;
FILE *ofptr=NULL;
char *bet=NULL;
bet=calloc(1,1);
if(bet==NULL){printf(”kevés memória! "); getch(); return 1;}
ifptr=fopen("C:\\szöveg.txt","r");
if(ifptr==NULL)
{printf("HIBAS MEGNYITAS Olvasasra");free(bet);return 2;}
ofptr=fopen("C:\\uj.txt","w");
if(ofptr==NULL) {printf("HIBAS MEGNYITAS Irasra");
fclose(ofptr);free(bet); getch();return 3;}
do
{
*bet=getc(ifptr); //……….. További lehetőségek
putc(*bet,ofptr);
}
while(!feof(ifptr));
fclose(ifptr); fclose(ofptr); free(bet);
return 0;
8
}
”Kivételkezelés” a C nyelvben
- közös hibakezelő rész
int FGV()
{
FILE *ifptr=NULL;
FILE *ofptr=NULL;
char *bet;
bet=calloc(1,1);
if(bet==NULL) goto hiba;
ifptr=fopen("c:\\szoveg.txt","r");
if(ifptr==NULL)goto hiba;
ofptr=fopen("c:\\uj.txt","w");
if(ofptr==NULL)goto hiba;
do{
*bet=getc(ifptr);
putc(*bet,ofptr);
} while(!feof(ifptr));
hiba:
if(ifptr!=NULL)fclose(ifptr); else{ printf("HIBA..");getch();}
if(ofptr!=NULL)fclose(ofptr); else{ printf("HIBA..");getch();}
if(bet!=NULL)free(bet); else{ printf("HIBA..");getch();}
return 0;
}
9
Kivételkezelés kezdetei - FORTRAN
Csak input – output műveletek közbeni hibák
kezelése
 err paraméter a hibakezelő rész címkéjével

open(file=’proba.file’,err=100, unit=2)
.
.
.
100 write(*,110)
110 format(’Hiba’)
10
Kivételkezelés kezdetei - COBOL
1.
2.
1,
Aritmetikai műveletek hibáinak kezelése
Input –output műveletek közbeni hibák
kezelése
DIVIDE N1 BY N2 GIVING N3 REMINDER N4 - eseti jellegű hibakezelés
ON SIZE ERROR DISPLAY ” HIBA”
- mint a FORTRAN-ban
2,
PROCEDURE DIVISION.
DECLERATIVES.
Hiba SECTION.
USE AFTER EXCEPTION PROCEDURE ON SajatFile.
Hibakezeles2.
DISPLAY ”HIBA”
END DECLERATIVES
11
Kivételkezelés kezdetei – PL/I





Kezdetleges kivételkezelő mechanizmus (60-as évek)
Néhány beépített kivétel pl. ZERODIVIDE
A kivételeknek nevük van, nem lehet – paraméterezni
– csoportosítani
Lehet saját kivételt készíteni – CONDITION
Lehet kivételt dobni - SIGNAL
12
Elvárások a kivételkezeléssel szemben
 meg
tudjuk különböztetni a hibákat,
 a hibát kezelő kód különüljön el a
tényleges kódtól,
 megfelelően tudjuk kezelni - a hiba
könnyen jusson el arra a helyre, ahol
azt kezelni kell,
 kötelező legyen kezelni a hibákat
13
Megoldás elemzése:
 Az
első elvárás, hogy meg tudjuk
különböztetni a hibákat - ez általában a
fellépés helyén történik.
A
második elvárás azt szeretné elérni,
hogy a programot először látó ember is
azonnal el tudja különíteni a hibakezelő
és a működésért felelős részeket. Ez
könnyebben továbbfejleszthető,
karbantartható programokhoz vezet.
14
A hiba jusson el oda, ahol kezelni kell
A
harmadik elvárás arra vonatkozik,
hogy - mivel a programok
többszintűek -, egy alacsonyabb
szinten jelentkező hibát (például ha
egy fájlt nem tudunk megnyitni, egy
üres veremből akar valaki kiolvasni)
nem biztos, hogy az adott szint le
tud kezelni, ezért a megfelelő helyre
kell eljuttatni.
15
Programnyelvek kivételkezeléseinek
összehasonlítási szempontjai:
– Hiba- vagy kivételkezelést ad-e a nyelv?
– Hogyan kell kivételeket definiálni-kiváltani-kezelni?
– Milyen a kivételkezelés szintaktikai formája / Mihez
kapcsolódik a kezelés: utasítás-, blokk- vagy
eljárás/függvényszintű?
– A kivételekből lehet-e kivételcsoportokat,
kivételosztályokat képezni, amelyeket a
kivételkezelőben egységesen lehet kezelni?
– Paraméterezhető-e a kivétel információ továbbadás
céljából?
– A kivétel kezelése után honnan folytatódjon a
program?
16
Programnyelvek kivételkezeléseinek
összehasonlítási szempontjai
– Van –e olyan nyelvi elem amely mind kivételes mind
normál módú futás esetén végrehajtódik („finally”) ?
– Tovább dobódhat-e a kivétel? Mi történik a kezeletlen
kivétellel?
– Megadható-e /meg kell-e adni, hogy egy alprogram
milyen lekezeletlen kivételeket küldhet?
– Párhuzamos környezetben vannak-e speciális
kivételek?
– Mi történik a váratlan kivételekkel?
– Kiváltható-e kivétel kivételkezelőben?
– Melyik kivételkezelő kezeli a kivételt?
17
Fejlett kivételkezelés :C++
try {
// kivétel keletkezhet
}
catch( típus [név]){
// kivétel kezelése
}
- Egy try blokkhoz több catch ág is tartozhat (mindegyik a saját kiv. tipust kapja
el
- catch(…) esetén minden kivételt elkap
- bármilyen típusú változót el lehet dobni kivételként
- kivétel dobása throw
try {
// mindenféle kivétel keletkezhet
}
catch( ….){
// minden kivételt elkap
}
18
Fejlett kivételkezelés :C++
int main() {
FILE *fptr;
try {
fptr=fopen("c:\\kw.txt", "r");
if( fptr ==NULL ) throw "baj van";
}
catch(int) {cout << "Exception1" ;}
catch(float){cout << "Exception2" ;}
catch(...) {cout << "Exception3" ; }
fclose(fptr);
}
- nincs finally
-kezeletlen kivétel továbbadódik a hívó függvény felé, ha a main() sem kezeli
meghívódik a terminate függvény => alapesetben az abort függvényt hívja
ez leállítja a prg. futását
-a kivétel kezelése után a vezérlés nem kerül vissza abba a blokkba ahol a
19
kivétel keletkezett – destruktor problémák (két dobott kivétel)
Fejlett kivételkezelés :C++
finally hiányának kezelése
class File{
private:FILE *f;
public:
File(char *filenev)
{ f=fopen(filenev,"r"); }
~File(){fclose(f);
cout<<"lezártam";}
};
void Fgv()
{ File f("c:\\k.txt");
try{}
// itt keletkezhet kiv.
catch(...){}
// kiv. kez
// a destruktor miatt fájl lezárás mindenképpen
}
int main()
{Fgv();
}
20
Fejlett kivételkezelés :C++

Lehetőség függvények fejlécében a dobható
kivételek részhalmazát megadni
throw "(" [type {"," type}] ")"
Pl.:
void f1(int x) throw(A,B,C);
Az f1 függvény csak A,B és C típusú kivételt generál, vagy
azok leszármazottait.
int f2(int x) throw () -- f2 nem válthat ki kivételt!
void f3 (int x)
-- f3 bármit kiválthat!
Ha specifikáltunk lehetséges kivételtípusokat, akkor minden
más esetben a rendszer meghívja az unexpected() függvényt,
melynek alapértelmezett viselkedése a terminate() függvény
meghívása. Ez a set_unexpected segítségével szintén
átállítható.
21
Fejlett kivételkezelés :C++

Példák:
class X {};
class Y: public X {};
class Z {};
void A() throw(X,Z) // A X,Y,Z-t dobhat
{ /* ... */ }
void B() throw(Y,Z)
{
A(); // unexpected, ha A X-t dob, ok Y, Z
típusúra
}
void C(); // semmit sem tudunk C-ről
void D() throw()
{
C(); // ha C bármit kivált, unexpected -t hív
throw 7; // unexpected-t hív
}
22
Fejlett kivételkezelés :C++
Előre definiált kivételek : bad_alloc; bad_cast; bad_typeid
#include <iostream>
using namespace std;
int main()
{
try
{
double *t = new double [1000000000];
}
catch(bad_alloc)
{
cout << "Elfogyott a memória\n";
}
system("pause");
return 0;
}
23
Fejlett kivételkezelés :Java
try {
...
throw new EgyException
(“parameter”);
}
catch (típus változónév) {
...
}
finally {
...
}
24
Fejlett kivételkezelés :Java
a
C++ szintaxistól nem sokban
különbözik.
A
kivételek mindig objektumok.
 finally
nyelvi konstrukció, ezzel a Java
megbízhatóbb programok írását segíti
elő.
 Nincs
catch(…) helyette catch(Exception e)
25
Fejlett kivételkezelés :Java
Egy függvény által kiváltható kivételek specifikálása:
void f(int x)throws EgyikException,
MasikException;
Minden kivétel a java.lang.Throwable leszármazottja. Ha olyan
kivételt szeretnénk dobni, amely nem a Throwable gyermeke, akkor
az fordítási hibát okoz.
public class ExExample {
void method1() {
try {
method2(3);
} catch (Exception e) { e.printStackTrace(); }
}
void method2(int i) throws Exception{
if (i == 0) trow new Exception("illegal argument: 0");
}
}
26
Fejlett kivételkezelés :Java
A kivételek két nagy csoportba
sorolhatóak:
- ellenőrzöttek: Exception leszármazottjai
-
Az ellenőrzött kivételek esetén fordítási hiba
lép fel, ha nincsenek specifikálva vagy
elkapva; illetve ha olyan ellenőrzött kivételt
kívánunk elkapni, amely hatókörön kívül van.
- nem-ellenőrzöttek: Error leszármazottjai
-
Futási időben keletkeznek
-
nem kötelező elkapni őket
27
Fejlett kivételkezelés :Java
 Azért
volt arra szükség, hogy a kivételeket
a fenti két csoportba sorolják, mert
számos olyan kivétel van, amely előre
nem látható és fölösleges lenne mindenhol
lekezelni őket. Ezeket a kivételeket
nevezzük nem-ellenőrzött kivételeknek.
 Például
nem ellenőrizzük le minden
utasítás végrehajtása előtt, hogy van-e
elég memóriánk stb.
28
Fejlett kivételkezelés :Java
Néhány predefinit nem ellenőrzött kivétel
(a RuntimeException leszármazottjai):
ArithmeticException, ClassCastException,
IndexOutOfBoundsException,
két alosztálya:
ArrayIndexOutOfBoundsException,
StringIndexOutOfBoundsException,
NullPointerException.
 az Error leszármazottjai pl.
OutOfMemoryError, StackOverflowError,
stb.

29
Fejlett kivételkezelés :Java

predefinit kivételek előfordulása:
class A {// ...
}
class B extends A {// ...
}
class C {
void X() {
A a= new A;
B b=(B)a; // ClassCastException
}
void Y() {
int ia[]= new int[10];
for (int i=1; i<=10; i++)ia[i]=0;
/* amikor i==10 lesz,
ArrayIndexOutOfBoundsException */
void Z() {
C c=null;
c.X(); // NullPointerException
}
}
}
30
Fejlett kivételkezelés :Java

Kivételek kezelése
try {
// utasítások
}
catch (MyException e) {
// utasítások MyException kezelésére
}
catch (AnotherException e) {
// utasítások AnotherException kezelésére
}
catch (Exception e) {
// utasítások AnotherException kezelésére
finally {
// mindig végrehajtódó utasítások
}
Fontos a catch ágak sorrendje
31
Fejlett kivételkezelés :C#
class Program
{
static void Main(string[] args)
{
string s = "asdfg";
int a = 0;
try
{
a = int.Parse(s);
Console.WriteLine(a);
}
catch (FormatException exc)
{
Console.WriteLine(exc.Message);
}
33
Fejlett kivételkezelés :C#
Példa 1:
using System;
class ExceptionTestClass {
public static void Main() {
int x = 0;
try {
–
int y = 100/x;
}
catch (ArithmeticException e) {
Console.WriteLine("ArithmeticException
Handler: {0}",
e.ToString());
}
catch (Exception e) {
Console.WriteLine("Generic Exception Handler: {0}",
e.ToString());
}
}
}
34
Fejlett kivételkezelés :C#
using System;
class ArgumentOutOfRangeExample {
static public void Main() {
….
try {
…
}
catch (ArgumentOutOfRangeException e) {
Console.WriteLine("Error: {0}",e);
}
finally {
Console.WriteLine(„It is always executed.");
}
}
}
35
Fejlett kivételkezelés :C#
Példapogram a throw használatára; több catch ág
class Program
{ static void Main(string[] args)
{
string s = "200";
int a = 0;
try
{ a = int.Parse(s);
if (a > 100) throw new Exception("nem lehet nagyobb,
mint 100!\n");
Console.WriteLine(a);
}
catch (FormatException ex) {
Console.WriteLine(ex.Message); }
catch (Exception exc) {
Console.WriteLine(exc.Message); }
Console.ReadKey();
} } Az a cath kapja el a hibát (felülről lefele haladva)
amely formális param. típusa vagy azonos a kivétel objektum
36
típusával vagy őse annak.
Fejlett kivételkezelés :C#
catch
- általános cach
{
Console.WriteLine("Hibásan adta meg a számot!");
.
.
}
Több catch() esetén a fordító hibát jelez, ha rossz a sorrend
37
Fejlett kivételkezelés :C#
38
Fejlett kivételkezelés :C#














System.Exception az alkalmazás végrehajtása során elıforduló hibákhoz
társított kivételek ősosztálya
System.SystemException a System névtér előre definiált
kivételtípusainak ősosztálya
System.ArgumentException egy metódus valamely aktuális
paramétere érvénytelen
System.ArgumentNullException null referencia nem megengedett
átadása
System.ArgumentOutOfRangeException az átadott paraméter az
érvényes tartományon kívülre esik
System.ArithmeticException aritmetikai műveletek és típuskonverzió
során előálló kivételek ősosztálya
System.DivideByZeroException nullával történő osztás
System.OverflowException túlcsordulási hiba
System.FormatException a paraméter formátuma nem megfelelő
System.IndexOutOfRangeException tömb túlindexelése
System.IO.IOException fájlkezeléssel kapcsolatos kivételek ősosztálya
System.NotImplementedException a meghívott metódus nem rendelkezik
implementációval
System.NullReferenceException egy változón keresztül hivatkozunk
egy objektum egy tagjára, és közben a változó null értékű
System.ApplicationException a felhasználó által definiált
kivételtípusainak ősosztálya
39
Fejlett kivételkezelés :C# class Program
{
static void Main(string[] args)
{ string s = "asdfg";
int a = 0;
try
{ a = átalakít(s);
Console.WriteLine(a);
}
catch (Exception exc)
{ Console.WriteLine(exc.Message); }
}
public static int átalakít(string s)
{ return átalakít2(s); }
public static int átalakít2(string s)
{ return int.Parse(s); }
}
kivétel
továbbadása
40
Kivételkezelés adatbáziskezelő
nyelvekben : PLSQL - ORACLE
Begin: blokk kezdet, exception : hibaág,
when … then : adott hiba kezelése, hiba
dobása raise
begin select a,b into l_a, l_b from foo where i=1;
dbms_output.put_line('a: ' || l_a || ', b: ' || l_b);
if (DATE>SYSDATE) then raise date_error endif;
exception
when date_error then dbms_output.put_line('*** Exc: date_err');
when too_many_rows then dbms_output.put_line('*** Exc: too
many rows');
when no_data_found then dbms_output.put_line('*** Exc: no
data');
end;
41
Kivételkezelés adatbáziskezelő
nyelvekben : TSQL - MSQL
Begin try – end try : a műveleti blokk
Begin catch – end catch : a hibakezelő
If … : adott hiba kezelése
BEGIN TRY
……………….
END TRY
BEGIN CATCH
if (error_number() = 1205)
SET ……
else
SET ……..
END CATCH
42
Kivételkezelés adatbáziskezelő
nyelvekben : FOXPRO
TRY
TRY – ENDTRY
CATCH : a hibakezelő
WHEN … : adott hiba kezelése
THROW kivételdobás
FINALLY
[ tryCommands ]
[ CATCH [ TO VarName ]
[WHEN l Expression ][ catchCommands ] ]
[ THROW [ eUserExpression ] ][ EXIT ]
[FINALLY[ finallyCommands ] ]
ENDTRY
43
Egyebek : migrációs segédprogramok
SQL Loader
 Feladata
: Adatok átvitele szövegfájlból
adatbázisba
 Exceptionfile – t hoz létre
– Az állományban azok a rekordok lesznek
amiket nem sikerült migrálni
44
Egyebek : Matlab
try
/utasítások/
catch
/utasítások/
end
A MATLAB nem nyújt lehetőséget sem újrakezdésre, sem
ún. final részre. A catch mindent elkap.
 Zéróosztás
nem ad hibát
a =1;
b = -5:0.2:4;
% ez egy lista 0.2-sével
c = 1:0.2:10;
f = a./b;
% elemenkénti osztás: ./
g = f*c' % skallár szorzás a c transzponáltjával
45
Összefoglalás








Hasznos eszköz a legtöbb új nyelvben megtalálható
Előnye, hogy jól elkülöníta a feladatokat megoldó kódot a
hibakezeléstől. A progr. átláthatóbb, mógosíthatóbb.
Obj. orientált nyelvekben a konstruktor kivételdobással értesítheti
a konstruktor hívóját.( arról értesíthet, hogy miért nem)
Hátrányok : kissé elrontja a program strukturáltságát ( hasonló a
goto-hoz). Veszélyes, ha olyankor történik kiv. dobás amikor nem
szabadna ( C++ destr.) Esetenként többletkód generálódik.
A kivételek előidézése és kezelése jelentős erőforrás igénnyel jár
és lassítja az alkalmazás végrehajtását az újabb osztályok
betöltése és a veremkezelési feladatok következtében.
Lehetőleg csökkentsük minimális mértékűre az általunk elıődézett
kivételek számát.
Kerüljük újabb kivétel elődézését a finally blokkban, ugyanis ha
egy kivételt nem fogunk el egyetlen catch blokkal sem, akkor
végrehajtódnak a finally blokkban elhelyezett utasítások, és az
újabb kivétel elődizése következtében az eredeti elvész.
Amennyiben egy programszakaszon belül több egymás utáni
utasításnál is elképzelhető kivétel keletkezése, úgy ne készítsünk
ezekhez külön try-catch-finally
szerkezeteket, mert nehezen
olvashatóvá tennék a kódot. Helyezzük el inkább az érintett
utasításokat egyetlen try blokkban, és készítsünk minden kivétel
46
típushoz catch blokkot.