Java - výjimky Tato kapitola ukazuje na několika příkladech práci s výjimkami v Javě. Klíčové pojmy: Výjimka, hierarchie výjimek, zachytávání výjimek, blok try-catch, tvorba vlastních výjimek, propagace výjimek
Výjimka - exception • • •
znamená vyjímečný stav, chyba programu nechceme, aby k ní došlo druhy výjimek: ◦ Error - závažné chyby, nedokážeme opravit, proto na ně nereagujeme (chyby JVM) ◦ Exception - kontrolovatelné výjimky, měli bychom na ni (nebo někdy i musíme - vstupy a výstupy) na ně reagovat
Reakce na výjimky •
na vznik výjimky můžeme reagovat více způsoby: ◦ ošetření výjimky pomocí bloku try-catch (zdrojový kód, ve kterém očekáváme, že může dojít ke vzniku chyby, uzavřeme do bloku try, hned za blokem try musí následovat blok catch, do kterého se program dostane, pokud k chybě dojde ◦ těsně za blokem catch můžeme ještě přidat blok finally, který se provede vždy, ať k chybě dojde nebo ne ◦ předání výjimky výše (propagace výjimek) - za deklarací metody, ve které může dojít k výjimce, napíšeme příkaz throws a za ním třídu výjimek, na které chceme reagovat (reakci na výjimku necháme na metodě, která bude tuto metodu volat): private void vstup() throws IOException {
...
}
Hierarchie a dědičnost výjimek
•
třída Exception zahrnuje veškeré kontrolovatelné výjimky různé druhy výjimek jsou potomky třídy Exception, např. ◦ ArrayIndexOutBoundsException (přetečení pole) ◦ ArithmeticException (např. dělení nulou) ◦ IOException (chyby vstupu a výstupu) ◦ NumberFormatException (chyba nesprávného formátu) můžeme si vytvořit i svoji třídu výjimky = potomka již existující třídy:
•
výjimku můžeme také v bloku try uměle vyvolat příkazem throw
• •
class MojeVyjimka extends Exception {
...
}
if (cislo == 0) throw new InputMismatchException() ;
2012-03-01
Java - výjimky
1/6
Příklad 1: Neošetřená výjimka
class UkazChybu1 { public static void main(String args[]) { int cisla[] = new int[5]; // deklarace pole typu int o délce 5 System.out.println("Pred generovanim chyby"); cisla[7] = 11; // přetečení indexu pole System.out.println("Po chybe"); } } /* výstup: Pred generovanim chyby Exception in thread "main" java.lang.ArrayIndexOutBoundsException: 7 at UkazChybu1.main(UkazChybu.java: 7) */
Příklad 2: Ošetřená výjimka
class UkazChybu2 { public static void main(String args[]) { int cisla[] = new int[5]; try { // blok kódu hlídající chyby System.out.println("Pred generovanim chyby"); cisla[7] = 11; // přetečení indexu pole System.out.println("Sem se nedostanu"); } catch(ArrayIndexOutOfBoundsException exc) { // zachycení výjimky System.out.println("*ERR: Preteceni indexu"); } System.out.println("Po chybe"); } } /* výstup: Pred generovanim chyby *ERR: Preteceni indexu Po chybe */
Příklad 3: Ošetření více chyb naráz class UkazChybu3 { public static void main(String args[]) { int cisla[] = new int[5]; // deklarace pole typu int o délce 5 int a = 5; int b = 0; try { // blok kódu hlídající chyby System.out.println("Pred generovanim chyby"); int c = a/b; // dělení nulou cisla[7] = 11; // přetečení indexu pole System.out.println("Sem se nedostanu"); } catch(ArrayIndexOutOfBoundsException exc) { // zachycení přetečení indexu System.out.println("****ERR: Preteceni indexu"); } catch(ArithmeticException exc) { // zachycení dělení nulou System.out.println("****ERR: Deleni nulou"); c = 0; } catch(Exception exc) { // zachycení jiné výjimky System.out.println("****ERR: Jakákoliv jiná chyba"); } System.out.println("Po chybe: c = " + c); } } /* výstup: Pred generovanim chyby ****ERR: Deleni nulou Po chybe: a = 0 */
2012-03-01
Java - výjimky
2/6
Příklad 4: Ošetření vstupu argumentů metody main z příkazové řádky:
public class VstupCisla { public static void main(String [] args) int pocet = 0; double prum = 0;
{
for (int i=0;i<args.length;i++) { if (jeToCislo(args[i])) { prum += Double.parseDouble(args[i]); pocet ++; System.out.println((i+1)+". vstup: "+args[i]); } else { System.out.println((i+1)+". vstup: Neni cislo: "+args[i]); } } System.out.println("\nZapsaných čísel: "+ pocet); System.out.println("Suma vsech "+ pocet +" čísel: "+prum); prum /= pocet; System.out.println("Prumer: "+prum); }
2012-03-01
Java - výjimky
3/6
}
private static boolean jeToCislo(String in) { try { Double.parseDouble(in); } catch (NumberFormatException ex) { return false; } return true; }
Příklad 5: Ošetření vstupu čísel v GUI, tvorba vlastních tříd výjimek: Pomocí GUI budeme chtít od uživatele, aby zadával jen určité hodnoty. První vstup musí být celé kladné číslo, druhý vstup bude kladné reálné číslo. Proto musíme ohlídat, aby uživatel:
• • •
zadal do vstupů obě hodnoty aby obě hodnoty byly číselné, první celé číslo obě hodnoty byly kladné
Tomu přizpůsobíme hlídání výjimek. Na kontrolu formátu vstupních dat použijeme výjimku na druhé napíšeme 2 vlastní třídy výjimek. NumberFormatException,
import import import import import
2
výjimky
si
java.awt.Container; java.awt.FlowLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.*;
/** * @author Marek Pernica + Jaroslav Janíček
2012-03-01
Java - výjimky
4/6
*/ public class Vyjimky extends JFrame { Container obsah; JButton but; JLabel vysledek; JTextField celeVstup,desetinneVstup; public Vyjimky() { nastavVlastnosti(); obsahOkna(); zviditelneni(); } private void nastavVlastnosti() { this.setTitle("Ohlídání výjimky"); this.setResizable(true); this.setSize(220,280); obsah = this.getContentPane(); obsah.setLayout(new FlowLayout()); } private void obsahOkna() { celeVstup = new JTextField(20); desetinneVstup = new JTextField(20); but = new JButton("Vyhodnotit"); vysledek = new JLabel("Vysledek: "); obsah.add(new JLabel("Zadej cele kladne cislo: ")); obsah.add(celeVstup); obsah.add(new JLabel("Zadej cele kladne desetinne cislo: ")); obsah.add(desetinneVstup); obsah.add(but); obsah.add(vysledek); }
but.addActionListener(new ReakceNaStisk()); // přihlášení posluchače události
/* vnitřní třída implementující patřičné rozhraní */ class ReakceNaStisk implements ActionListener { public void actionPerformed(ActionEvent e) { kontrola(); } private void kontrola() { try { porovnani(celeVstup.getText(),desetinneVstup.getText()); int i = Integer.parseInt(celeVstup.getText()); double j = Double.parseDouble(desetinneVstup.getText()); mensiNezNula(i,j); vysledek.setText("Výsledek: \n celé " + i + "\n desetinné " + j); } catch (Nezadano e) { vysledek.setText("Prázdný vstup, debile."); } catch (NumberFormatException e) { vysledek.setText("Napsal jsi špatný formát čísla!"); } catch (MensiNezNula e) { vysledek.setText("Menší než nula. NULA, NULA."); } catch (Exception e) { vysledek.setText("Došlo k neznámé chybě.");
2012-03-01
Java - výjimky
5/6
} }
System.out.println(e.toString());
}
/* řízení předáno výš, metodě, která metodu volala */ private void porovnani(String a,String b) throws Nezadano { /* vytvoření instance vlastní výjimky */ if (a.equals("")) throw new Nezadano(); if (b.equals("")) throw new Nezadano(); } private void mensiNezNula (int a, double b) throws MensiNezNula { if(a <0 || b<0) throw new MensiNezNula(); } private void zviditelneni() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } } ----------------------------------------------------------------------------------/** * @author Marek Pernica + Jaroslav Janíček */ public class Nezadano extends Exception { public Nezadano () { super("Nezadaná hodnota"); }
} ----------------------------------------------------------------------------------/** * @author Marek Pernica + Jaroslav Janíček */ public class MensiNezNula extends Exception {
}
public MensiNezNula () { super("Hodnota čísla je menší než nula"); }
2012-03-01
Java - výjimky
6/6