<< Dvojrozmerné polia | Obsah | Práca so súbormi a adresármi operačného systému >>
Výnimky sú riadiaci mechanizmus, ktorý sa používa, keď nejaká operácia nedokáže prebehnúť štandardným spôsobom alebo nedokáže vrátiť očakávanú hodnotu. Uveďme si pár príkladov:
Turtle[] korytnacky = new Turtle[-5];
a program sa dozvie, že vytvárate pole dĺžky -5, ale také pole vytvoriť nevie.
V starších programovacích jazykoch vám takáto situácia spôsobí okamžité ukončenie alebo zamrznutie celej aplikácie, čo je veľmi nepríjemné. Často program iba vypíše ničnehovoriacu hlášku ako "segmentation fault" alebo "fatal error", ktorá mu nepovie ani to, kde a ani aká výnimočná situácia nastala.
Aké výhody oproti tomuto má výnimka? Za prvé, výnimka má svoj názov, ktorý nám (po preklade z angličtiny) naznačí, aká udalosť sa stala.
Akých výnimiek by sme sa dočkali v prípade predchádzajúcich príkladov?
java.lang.ArithmeticException: / by zero
- výnimka pri aritmerickej operácii: delenie nulou
java.lang.NegativeArraySizeException
- výnimka zápornej veľkosti poľa
java.lang.ArrayIndexOutOfBoundsException: 15
- výnimka indexu poľa mimo hranice poľa: 15-ty prvok
java.lang.NullPointerException
- výnimka ktorá sa vyhodí ak namiesto objektu máme v premennej null
a chceme cez túto premennú volať metódu.
Vytvorme si príklad metódy korytnačky, ktorá vráti true
ak priemer prvých k
prvkov poľa na vstupe je väčší ako 0, inak vráti false
. Chceme aby táto metóda vždy vrátila nejakú hodnotu, to znamená, že by mala byť odolná voči všetkým zlým vstupom. Napíšme si najprv metódu, ktorá verí, že všetky vstupy budú pekné a nespôsobia výnimočný stav:
Čo by sa stalo v prípade, ak v premennej pole bude null
? Telo for cyklu vyhodí výnimku NullPointerException
, lebo chceme pristupovať do poľa, ktoré neexistuje. Vyrobíme si podmienku, ktoré nám zabezpečí, že ak nastane tento prípad, tak sa v tomto prípade korektne vráti ako výstupná hodnota metódy false. (to znamená, že priemer prvých k
prvkov nie je väčší ako nula).
null
v premennej pole však nie je jediné, čo môže postihnúť bezchybné fungovanie metódy.
Premenná k
môže mať hodnotu nula. V tom prípade sa for cyklus nevykoná ani raz (lebo 0 < 0 je false) a program sa bude snažiť deliť nulou teda vyhodí ArithmeticException
. Dodáme teda ďalšiu podmienku.
Ďalšia chyba vstupu môže byť, že pole môže mať dĺžku nula. Zasa pridáme podmienku.
Další problém môže byť, keď k
je väčšie ako dĺžka poľa. V tomto prípade program vyhodí výnimku ArrayIndexOutOfBoundsException
pri snahe pripočítať prvok poľa ktorý je prvý za posledným prvkom poľa. Zasa pridáme ďalšiu podmienku ktorá nám opraví k
na dĺžku poľa.
Výsledný kód vyzerá nasledovne:
Vyrobme si teraz nový program, ktorý bude vracať súčet čísiel, ktoré sa nachádzajú v reťazci. Budeme potrebovať reťazec rozdeliť na slová a každé slovo sa pokúsiť pretransformovať na int
. Na to použijeme funkciu Integer.parseInt(...)
.
Samotný kód metódy vyzerá nasledovne.
Tento program však môže pri zlom vstupe tiež vyhodiť výnimku, konkrétne NumberFormatException
, a to vtedy, ak budeme mať viac medier medzi číslami, alebo ak použijeme vo vstupnom reťazci aj iné znaky ako cifry. V takomto prípade si už jednou podmienkou nepomôžeme a museli by sme robiť kadejaké testy, prechádzať reťazec a podobne.
Veľká výhoda výnimky je, že ju môžeme odchytiť, a ak je to možné, vysporiadať sa s týmto stavom v programe. Napríklad môžeme poprosiť používateľa nech zadá iný vstup alebo mu minimálne namiesto výnimky vypísať nejakú hlášku v ľudskej reči.
Odchytávanie výnimky robíme tak, že najprv si ohraničíme oblasť, kde očakávame, že by mohla nastať výnimka s ktorou sa chceme vysporiadať do bloku try, a za ním napíšeme blok catch ktorý sa aktivuje, iba ak nastala výnimka. Ak výnimka nenastane prebehnú všetky príkazy v bloku try akoby tam blok try ani nebol. Blokov catch môže byť jeden alebo viac - pre každý typ výnimky jeden. Syntax je teda nasledovná:
Čo teda urobíme v našom príklade? Ak sa nám nepodarí stransformovať číslo v reťazci na číslo typu int
, telo for cyklu vyhodí výnimku NumberFormatException
. Vyrobíme si teda bloky try a catch, ktoré nám zabezpečia kód tým, že sa takáto výnimka odchytí, dané slovo budeme ignorovať a používateľovi vypíšeme hlášku, že mal nejaké chyby vo vstupe.
Ak nastane výnimka a nemáme príslušný catch blok, ktorý by odchytával správnu výnimku, program skončí s chybou. Aby to nebolo také jednoduché, tak za blokmi catch môže nasledovať ešte jeden blok finally. Podľa definície je to blok, ktorý sa vykoná vždy bez ohľadu na to, či výnimka vyhodená vo vnútri try bloku bola odchytená alebo nie. Používa sa obvykle na korektné ukončenie sieťového spojenia, na korektné zatvorenie súboru alebo odhlásenie z databázy. Ak výnimka nebola odchytená niektorým catch blokom, tak sa ešte vykoná blok finally a až potom program skončí s chybou.
K výnimkám je ešte potrebné spomenúť, že Java pozná dva typy výnimiek:
FileNotFoundException
, sa stretneme pri otváraní súborov.