13. V²jimky
V²jimka (exception) je definovßna jako udßlost, kterß nastane
b∞hem provßd∞nφ programu a kterß naru╣φ normßlnφ b∞h instrukcφ. V²jimka je
vyvolßna nap°φklad p°i chybnΘm otev°enφ souboru, p°i p°ekroΦenφ mezφ
pole, p°i aritmetickΘ chyb∞ apod. Mechanismus v²jimek umo╛≥uje tyto chybovΘ
stavy zachytit a o╣et°it. K tomu slou╛φ dvojice blok∙ try
a catch, jejich╛ syntaxe je nßsledujφcφ:
try {
// hlφdan² blok
} catch( t°φdaV²jimek1 jmΘnoProm∞nnΘ1 ) {
// o╣et°enφ v²jimky
} catch( t°φdaV²jimek2 jmΘnoProm∞nnΘ2 ) {
// o╣et°enφ v²jimky
}
- Hlφdan² blok try - uzavφrß kritickou Φßst programu, kde
"m∙╛e" b²t vyvolßna v²jimka.
- ZßchytnΘ bloky catch - o╣et°ujφ v²jimky, musφ nßsledovat
bezprost°edn∞ za blokem try a m∙╛e jich b²t libovoln² poΦet.
Vyvolanß v²jimka je objekt a ka╛d² zßchytn² blok zachycuje jeden typ v²jimek (t°φdaV²jimek1, t°φdaV²jimek2). Na vyvolanou
v²jimku v zßchytnΘm bloku odkazuje referenΦnφ prom∞nnß (jmΘnoProm∞nnΘ1,
jmΘnoProm∞nnΘ2). Pokud v hlφdanΘm bloku v²jimka:
Priklad 13.1. |
Metoda nactiBajt otev°e soubor zadanΘho jmΘna (1) a
naΦte z n∞j prvnφ byte, kter² vypφ╣e na standardnφ v²stup (1) (2).
void nactiBajt(String jSouboru) {
try {
FileInputStream soubor = new FileInputStream(jSouboru); // (1)
System.out.println(soubor.read()); // (2)
} catch(FileNotFoundException e) { // (3)
System.out.println("Soubor " + jSouboru + "nenalezen."); // (4)
} catch(IOException e) { // (5)
System.out.println("Chyba p°i Φtenφ souboru " + jSouboru);// (6)
}
}
P°i pokusu otev°enφ souboru se m∙╛e stßt, ╛e tento nebude nalezen
(nastane v²jimka FileNotFoundException), nap°. pokud soubor
neexistuje nebo je chybn∞ zadanΘ jmΘno. Pokud tento v²jimeΦn² stav
nastane, je zachycen blokem catch na °ßdce (3) a vypφ╣e se
chybovß zprßva (4).TakΘ p°i Φtenφ m∙╛e nastat chyba (v²jimka IOException), nap°. pokud soubor nenφ urΦen
pro Φtenφ nebo nastane chyba za°φzenφ. Tento stav
zachycuje blok catch na °ßdce (5) a vypφ╣e se chybovß zprßva (6). Pokud v╣e prob∞hne bez problΘm∙, pokraΦuje program za zßchytn²mi bloky (metoda
skonΦφ).
|
|
V╣imn∞te si, ╛e dφky v²jimkßm je d∙sledn∞ odd∞len "u╛iteΦn² k≤d" od k≤du,
kter² pouze o╣et°uje chyby. V²jimka jednΘ t°φdy m∙╛e b²t navφc vyvolßna
v hlφdanΘm bloku na n∞kolika mφstech a k o╣et°enφ postaΦuje jeden blok catch. Ve srovnßnφ s klasick²m zp∙sobem testovßnφ chyb (p°φkazem if) je
zachycovßnφ chyb pomocφ v²jimek mnohem p°ehledn∞j╣φ.
13.1. T°φdy v²jimek
RodiΦovskou t°φdou v╣ech v²jimek je Throwable (z balφku java.lang), kterß mß standardn∞ dva p°φmΘ potomky:
- Error - reprezentuje fatßlnφ chyby, kterΘ by nem∞ly b²t
zachycovßny, nebo╗ se z nich nelze zotavit (chyba JVM apod.).
- Exception - slou╛φ jako rodiΦovskß t°φda pro v╣echny ostatnφ
v²jimky.
╚ßst stromu v²jimek t°φdy Exception vypadß takto: ![vyjimky.gif](/file/23392/Chip_2000-10_cd1.bin/chplus/Java/images/vyjimky.gif) Dφky objektovΘ hierarchii v²jimek je mo╛nΘ zachytit vφce t°φd
v²jimek v jednom catch bloku - jedna t°φda v²jimek v sob∞ zahrnuje
i v╣echny potomky tΘto t°φdy. Proto╛e v╣ak u zßchytn²ch blok∙ zßle╛φ na po°adφ, (2) je mo╛nΘ n∞kterΘ potomky zachytit zvlß╣╗
a ostatnφ nechat bloku zachycujφcφ v²jimky rodiΦovskΘ t°φdy:
Priklad 13.2. |
try {
// ...
} catch(ArithmeticException e) {
// zachycenφ v²jimek t°φdy ArithmeticException
} catch(Exception e) {
// zachycenφ v╣ech v²jimek t°φdy Exception , tj.
// InterruptedException , RuntimeException ,
// IndexOutOfBoundsException atd. (krom∞ ArithmeticException )
}
|
|
Programßtor si samoz°ejm∞ m∙╛e vytvo°it vlastnφ t°φdu v²jimek - staΦφ
vytvo°it potomka n∞kterΘ z t°φd v²jimek z Java Core API (nedoporuΦuje
se v╣ak jako rodiΦovskou t°φdu pou╛φt p°φmo Throwable).
13.2. Vyvolßnφ v²jimky
V²jimky je mo╛nΘ programov∞ vyvolßvat p°φkazem throw. Jeho syntaxe je:
throw instanceV²jimky ;
V²jimka instanceV²jimky musφ b²t instancφ t°φdy Throwable
nebo jejφch potomk∙.
Priklad 13.3. |
Vyvolßnφ v²jimky t°φdy ArithmeticException se provede pomocφ:
throw new ArithmeticException();
|
|
13.3. Deklarace v²jimek
V╣echny v²jimky, kterΘ mohou v danΘ metod∞ nastat, musφ b²t zachyceny nebo deklarovßny (viz 11.2.2.), jinak
p°ekladaΦ ohlßsφ chybu. (3)
Druh² p°φpad znamenß, ╛e
metoda p°enechßvß o╣et°enφ deklarovan²ch v²jimek volajφcφ metod∞ - dochßzφ
k tzv. propagaci v²jimek (viz 13.4.). Volajφcφ metoda
op∞t musφ tyto (resp. v╣echny) v²jimky zachytit nebo deklarovat.Deklarace v²jimek se pou╛φvß zejmΘna v p°φpad∞, ╛e na danΘ ·rovni (nap°. p°φmo
v knihovn∞) nenφ vhodnΘ provßd∞t o╣et°enφ v²jimky (nenφ mo╛nΘ rozhodnout, jak
by m∞lo vypadat o╣et°enφ):
Priklad 13.4. |
Konstruktor FileInputStream(), kter² otevφrß soubor zadanΘho jmΘna
(viz p°φklad 13.1.) neo╣et°uje p°φpad, ╛e soubor nenφ nalezen
(nastane v²jimka FileNotFoundExeption) a p°enechßvß tuto starost
volajφcφ metod∞. Ta m∙╛e nechat u╛ivatele zadat jmΘno souboru znovu, doplnit
si jmΘno sama, skonΦit atd.
|
|
13.4. Propagace v²jimek
V²jimka m∙╛e b²t uvnit° metody vyvolßna dv∞ma zp∙soby:
- p°φkazem throw (viz 13.2.),
- volßnφm metody, kterß v²jimku deklaruje (viz 13.3.).
Pokud nenφ vyvolanß v²jimka zachycena blokem catch (viz str. 13) v metod∞, kde byla vyvolßna, je p°edßna o ·rove≥ v²╣
(volajφcφ metod∞). Takto se v²jimka rekurzivn∞ p°edßvß dokud nedojde k jejφmu
zachycenφ a v krajnφm p°φpad∞ je zachycena runtime systΘmem, kter² zachycuje
v╣echny v²jimky (standardn∞ vypφ╣e chybovou zprßvu a ukonΦφ program). Tento
mechanismus se naz²vß propagace v²jimek.
Priklad 13.5. |
public class Test {
public static void main(String[] args) {
try {
a(); // (1)
} catch(Exception e) { // (2)
System.out.println("V²jimka zachycena.");
e.printStackTrace(); // (3)
}
}
static void a() throws Exception { // (*)
b(); // (4)
}
static void b() throws Exception { // (**)
throw new Exception(); // (5)
}
}
Program zaΦφnß metodou main(), kde je volßna metoda a() (1), kterß
nßsledn∞ volß metodu b() (4), v nφ╛ je vyvolßna v²jimka Exception
(5). Tato v²jimka nenφ metodou b() zachycena a je proto propagovßna do
volajφcφ metody a(). Zde rovn∞╛ nenφ zachycena a je dßle propagovßna do
metody main(), kde je koneΦn∞ zachycena (2) a zp∙sobφ v²pis (3):
Vyjimka zachycena.
java.lang.Exception
at Test.b(A.java:16)
at Test.a(A.java:12)
at Test.main(A.java:4)
Ob∞ metody, v nich╛ m∙╛e b²t v²jimka vyvolßna, ale nenφ zachycovßna, ji
deklarujφ (*), (**).
|
|
13.5. Runtime v²jimky
Zvlß╣tnφ postavenφ mezi v²jimkami majφ tzv. runtime v²jimky -
instance t°φdy RuntimeException a jejφch potomk∙. Tyto v²jimky nemusφ
b²t v metodßch zachycovßny ani deklarovßny.Runtime v²jimky toti╛ reprezentujφ chyby, kterΘ mohou nastat "kdekoliv"
v programu. Jednß se nap°φklad o ArrayIndexOutOfBoundsException
(p°eteΦenφ indexu pole) nebo ArithmeticException (aritmetickß chyba -
celoΦφselnΘ d∞lenφ nulou) apod. O╣et°ovßnφ t∞chto v²jimek by mnohdy znamenalo zbyteΦnou prßci navφc, nebo╗
nap°φklad ve for cyklu lze snadno zajistit, aby index pole meze
nep°ekroΦil. Pokud by ArrayIndexOutOfBoundsException nebyla runtime
v²jimkou, bylo by ji nutnΘ v ka╛dΘ metod∞, kterß pole pou╛φvß zachytit
nebo deklarovat.
13.6. Koncov² blok (finally)
Dvojici blok∙ try - catch (viz str. 13) je mo╛nΘ
roz╣φ°it o nepovinn² koncov² blok finally nßsledovn∞:
try {
// hlφdan² blok
} catch( t°φdaV²jimek1 jmΘnoProm∞nnΘ1 ) {
// o╣et°enφ v²jimky
} finally {
// zde uzav°en² k≤d se provede v╛dy
}
Koncov²m blokem program pokraΦuje po ukonΦenφ hlφdanΘho i zßchytnΘho
bloku (tj. a╗ u╛ v²jimka nastane nebo ne). Koncov² blok se vykonß dokonce
i v p°φpad∞, ╛e:
- je v try bloku vyvolßna v²jimka, kterou ╛ßdn² catch
blok nezachycuje, nap°. runtime v²jimka (viz 13.5.) -
a to je╣t∞ p°ed propagacφ tΘto v²jimky,
- je v hlφdanΘm bloku vyvolßn p°φkaz return (viz 9.13.).
|