Výjimky
K moderním programovacím jazykům neodmyslitelně patří zpracování výjimek. U Smalltalku tomu není jinak, ovšem pár rozdílů lze najít. Např. oproti Javě zde virtuální stroj hraje mnohem méně významnou úlohu.
Ve Smalltalku hrají výjimky velmi významnou roli, což je mimo jiné dáno tím, že kontrola kódu v době kompilace je z principu velmi omezená.
Nejjednodušší zpracování výjimek
Nejčastěji používanou konstrukcí je použití metody ifError: třídy BlockContext.
[ localVar := 42 / 0 ] ifError: [ Transcript show: 'chyba' ]
Protože se jedná o výraz, lze ho výhodně použít pro bezpečné přiřazení
localVar := [ 42 / 0 ] ifError: [ Float infinity ]
v našem případě se vygeneruje výjimka ZeroDivide, tedy dělení nulou
Blok pro zpracování výjimky může mít dle potřeby až dva parametry:
- textový popis výjimky
- příjemce výjimky
[ 42 / 0 ]
ifError: [:error :receiver | Transcript show: error. receiver inspect ]
"vypíše do Transcriptu řetězec 'ZeroDivide' a otevře inspector
pro objekt 42 třídy Integer"
Zpracování výjimek
[ 42 / 0 ] on: ZeroDivide do: [:exception | Transcript show: 'Dělení nulou' ].
metoda on:do: třídy BlockContext má dva parametry
- handler výjimky či množinu handlerů
- blok vykonávaný v případě výskytu výjimky
[ 42 / 0 ] on: ZeroDivide, Warning do: [:exception | Transcript show: 'Chyba' ].
"nebo:"
[ 42 / 0 ] on: (ExceptionSet with: ZeroDivide with: Warning)
do: [:exception | Transcript show: 'Chyba' ].
Užitečná může být varianta onDNU:do:, která zachytává výjimky třídy MessageNotUnderstood
Generování výjimek
Základní třídou pro výjimky je třída Exception. Z ní je možné odvodit další typy výjimek.
Nejčasněji používané odvozené třídy výjimek jsou např. Error, Warning, Notification, Halt apod.
Výjímky se generují metodou signal
Error signal.
Error signal: 'Text chyby'.
Warning signal: 'Text varování'.
Notification signal: 'Text upozornění'.
Reakce na výjimku
Výjimky mohou umožňovat návrat (isResumeable). V tom případě nám poslouží metody resume nebo resume:, popřípadě retry či retryUsing.
Výjimku propustíme voláním metody pass
Blok zpracování výjimky můžeme opustit zavoláním metody return či return:
Finalizační kód
Pokud například pracujeme se souborem, chceme, aby byl na konci práce vždy uzavřen. V případě, že však nastane neošetřená výjimka, k uzavření souboru dojít nemusí. Pro tento a podobné účely je vhodné použít následující obrat:
[ "zpracovávej soubor" ] ensure: [ "uzavři soubor" ].
K uzavření souboru pak dojde za všech okolností. Pokud v prvním bloku dojde k výjimce, je zpracována standardním způsobem.
Příklad 1
Zpracování bez výskytu chyby
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/1.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
"akce"
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
after
val: 42
block: block result
"
Příklad 2
Vyskytla se chyba
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
"akce"
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
ex after
val: nil
block: exception block result
"
Příklad 3
Návrat
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex resume.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
after
val: nil
block: block result
"
Příklad 4
Návrat s vnucením hodnoty
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex resume: 6*9.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
after
val: 54
block: block result
"
Příklad 5
Nový pokus
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex retry.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr
"
before
ex before
... neustále cyklí ...
"
Příklad 6
Provedení náhradního bloku
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex retryUsing: [val := 42/1. 'retryBlock'].
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
val: 42
block: retryBlock
"
Příklad 7
Propuštění výjimky
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex pass.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
... vyskočí dialog ZeroDivide ...
"
Příklad 8
Předčasný návrat z výjimkového bloku (obdoba ^)
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex return.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
val: nil
block: nil
"
Příklad 9
Předčasný návrat z výjimkového bloku s návratovou hodnotou
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex return: 'předčasná hodnota'.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
val: nil
block: předčasná hodnota
"
Příklad 10
Transformace výjimky
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
ex resignalAs: Notification new.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
after
val: nil
block: block result
"
Příklad 11
Chyba ve výjimkovém bloku
| block val |
block := [ Transcript clear; show: 'before'; cr.
val := 42/0.
Transcript show: 'after'; cr.
'block result'
] on: Error do: [:ex | Transcript show: 'ex before'; cr.
42/0.
Transcript show: 'ex after'; cr.
'exception block result'
].
Transcript show: 'val: '; show: val; cr.
Transcript show: 'block: '; show: block; cr.
"
before
ex before
... vyskočí dialog ZeroDivide ...
"
Odkaz na tuto stránku
- Články, poslední úprava dne 17 Únor 2010 v 11:18:52 uživatelem localhost
|