Programovanie (1) v C/C++
1-INF-127, ZS 2024/25
Letný semester, prednáška č. 4: Rozdiel medzi revíziami
Riadok 90: | Riadok 90: | ||
* Takto sa v zásobníku volaní metód pokračuje nižšie a nižšie, až kým je nájdená metóda, ktorá danú výnimku odchytí a spracuje. | * Takto sa v zásobníku volaní metód pokračuje nižšie a nižšie, až kým je nájdená metóda, ktorá danú výnimku odchytí a spracuje. | ||
* Ak sa takáto metóda na zásobníku volaní nenájde – čiže je výnimka vyhodená aj metódou <tt>main</tt> na jeho dne – typicky dôjde k ukončeniu vykonávania programu a k vypísaniu informácií o výnimke (vrátane zásobníka volaní funkcií) na štandardný chybový výstup; ide tu ale o zjednodušenie. | * Ak sa takáto metóda na zásobníku volaní nenájde – čiže je výnimka vyhodená aj metódou <tt>main</tt> na jeho dne – typicky dôjde k ukončeniu vykonávania programu a k vypísaniu informácií o výnimke (vrátane zásobníka volaní funkcií) na štandardný chybový výstup; ide tu ale o zjednodušenie. | ||
+ | |||
+ | === Chytanie a ošetrovanie výnimiek === | ||
+ | |||
+ | <!-- catch 1 blok, catch viacero blokov, finally, spomenut niektore metody triedy Exception/Throwable --> | ||
=== Hierarchia výnimiek === | === Hierarchia výnimiek === | ||
<!-- tri zakladne typy catch or throw requirement --> | <!-- tri zakladne typy catch or throw requirement --> | ||
− | |||
− | |||
− | |||
− | |||
=== Hádzanie nových výnimiek === | === Hádzanie nových výnimiek === |
Verzia zo dňa a času 16:47, 4. marec 2021
Obsah
Oznamy
- Počas najbližších cvičení, čiže v stredu 10. marca od 11:30 do 13:00 bude prebiehať prvý test. Bude pozostávať z troch úloh zameraných na látku z prvých troch týždňov, ktorých riešenia bude potrebné odovzdávať na testovač. Po dobu riešenia testu je potrebná účasť na stretnutí „Cvičenia” v MS Teams.
- V stredu tiež budú zverejnené dve nebodované úlohy k štvrtým cvičeniam, zamerané na látku z dnešnej prednášky. Ďalšie podobne zamerané úlohy budú zverejnené na cvičeniach budúci týždeň.
- Prvú domácu úlohu je potrebné odovzdať najneskôr do začiatku budúcej prednášky, čiže do pondelka 15. marca, 9:00.
Výnimky
Mechanizmus výnimiek (angl. exceptions) slúži v Jave na spracovanie chýb a iných výnimočných udalostí, ktoré môžu počas vykonávania programu nastať. Doposiaľ sme v našich programoch takéto situácie viac-menej ignorovali – napríklad sme obvykle predpokladali, že vstup vždy spĺňa požadované podmienky, že súbor, z ktorého sa pokúšame čítať, vždy existuje, atď. Dôvodom bola predovšetkým prílišná prácnosť ošetrovania chýb pomocou podmienok a neprehľadnosť programov, ktoré takéto podmienky obsahujú.
Uvažujme napríklad nasledujúci jednoduchý program, ktorý zo vstupu načíta prirodzené číslo n nasledované n celými číslami, ktoré postupne poukladá do poľa dĺžky n. Následne číta zo vstupu postupnosť indexov v rozmedzí 0 až n-1 a po každom načítaní indexu i zvýši hodnotu a[i] o jedna. Načítavanie vstupu sa ukončí po načítaní reťazca "KONIEC".
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int a[] = new int[n];
for (int i = 0; i <= n - 1; i++) {
a[i] += scanner.nextInt();
}
String next = scanner.next();
while (!next.equals("KONIEC")) {
a[Integer.parseInt(next)]++;
next = scanner.next();
}
}
Vykonávanie tohto programu môže skončiť chybou viacerými rôznymi spôsobmi: používateľ napríklad môže namiesto niektorého čísla zadať nečíselný reťazec; číslo n môže ďalej zadať ako záporné, čím vznikne chyba pri pokuse o alokovanie poľa; niektorý z ním zadaných indexov do poľa tiež nemusí byť v požadovanom rozmedzí. Po pokuse o ošetrenie týchto chýb pomocou podmienok dostávame nasledujúci horibilný program.
/** Nasledujuci kod je ukazkou toho, ako sa osetrovanie chyb v Jave NEMA robit. */
/** Metoda, ktora zisti, ci je retazec nebielych znakov reprezentaciou celeho cisla. */
private static boolean isInteger(String s) {
Scanner stringScanner = new Scanner(s);
return stringScanner.hasNextInt();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = 0;
if (scanner.hasNextInt()) {
n = scanner.nextInt();
if (n < 0) {
System.err.println("Pocet prvkov pola nemoze byt zaporny.");
System.exit(2);
}
} else {
System.err.println("Vstup sa nezacina cislom.");
System.exit(1);
}
int a[] = new int[n];
for (int i = 0; i <= n - 1; i++) {
if (scanner.hasNextInt()) {
a[i] += scanner.nextInt();
} else {
System.err.println("Niektory z prvkov pola nebol zadany ako cele cislo.");
System.exit(3);
}
}
String next = scanner.next();
while (!next.equals("KONIEC")) {
if (isInteger(next)) {
int i = Integer.parseInt(next);
if (i >= 0 && i <= n - 1) {
a[i]++;
} else {
System.err.println("Niektory z indexov do pola je mimo povoleneho rozmedzia.");
System.exit(5);
}
} else {
System.err.println("Niektory z indexov do pola nebol zadany ako cele cislo.");
System.exit(4);
}
next = scanner.next();
}
}
Vidíme, že už aj pri takto jednoduchej úlohe dostávame pomerne rozsiahly program, v ktorom väčšinu kódu zaberá práve spracovanie chýb. Ešte nepríjemnejšou je však skutočnosť, že ošetrovanie chýb je potrebné implementovať v mieste programu, kde táto chyba vznikla. To vedie k prelínaniu podstatných častí programu s časťami, ktoré slúžia iba na spracovanie chýb, v dôsledku čoho sa kód stáva veľmi neprehľadným. Z uvedených dôvodov sme až doposiaľ podobné chybové udalosti väčšinou ignorovali.
V praxi je ale nutné podobné chyby náležite poošetrovať – nie je totiž napríklad prípustné, aby textový editor spadol zakaždým, keď sa jeho používateľ pokúsi otvoriť súbor s neexistujúcim názvom. Výnimky poskytujú spôsob, ako spracovanie chybových udalostí realizovať podstatne efektívnejším spôsobom, než v ukážke vyššie. Medzi ich základné prednosti totiž patria:
- Možnosť oddelenia kódu na spracovanie chýb od zvyšku kódu.
- Možnosť jednoduchým spôsobom ponechať spracovanie chyby na volajúcu metódu v prípade, že sa to javí ako vhodnejšie riešenie.
- Možnosť využívať pri spracúvaní chýb prostriedky objektovo orientovaného programovania.
Mechanizmus výnimiek v Jave
Pod výnimkou (angl. exception) sa v Jave rozumie inštancia špeciálnej triedy Exception, prípadne jej nadtriedy Throwable, reprezentujúca nejakú výnimočnú udalosť. Trieda Exception má pritom množstvo podtried reprezentujúcich rôzne typy chybových udalostí.
- Výnimka môže počas vykonávania nejakej metódy f vzniknúť buď tak, že ju vyhodí JVM (napríklad pri delení nulou alebo pri prístupe k neexistujúcemu prvku poľa), alebo tak, že ju vyhodí sama táto metóda pomocou príkazu throw (detaily nižšie).
- Vzniknutá výnimka môže byť priamo odchytená a ošetrená v rámci danej metódy f. V opačnom prípade je vykonávanie metódy ukončené a výnimka je posunutá metóde g, ktorá metódu f volala (posunieme sa teda v zásobníku volaní metód o úroveň nižšie).
- V metóde g sa na celú situáciu dá pozerať tak, akoby výnimka vznikla pri vykonávaní príkazu, v rámci ktorého sa volala metóda f. Opäť teda môže byť výnimka buď odchytená a ošetrená, alebo rovnakým spôsobom predaná metóde, ktorá volala metódu g (aj v takom prípade hovoríme, že metóda g vyhodila výnimku, hoci reálne výnimka vznikla už v metóde f).
- Takto sa v zásobníku volaní metód pokračuje nižšie a nižšie, až kým je nájdená metóda, ktorá danú výnimku odchytí a spracuje.
- Ak sa takáto metóda na zásobníku volaní nenájde – čiže je výnimka vyhodená aj metódou main na jeho dne – typicky dôjde k ukončeniu vykonávania programu a k vypísaniu informácií o výnimke (vrátane zásobníka volaní funkcií) na štandardný chybový výstup; ide tu ale o zjednodušenie.