Ošetření výjimek
Výjimky lze v Javě ošetřovat třemi základními způsoby:1. Propagace výjimky: výjimka není ošetřena v metodě, ve které vznikla, je předána do nadřazené úrovně.
2. Ošetření metodou chráněných bloků: Výjimka je ošetřena v metodě, ve které vznikla.
3. Kombinace obou způsobů: Výjimka (částečně) ošetřena v metodě, kde vznikla. Dále je předána do nadřazené úrovně. Třetí metoda je nejčastěji používána, umožňuje komplexní obsloužení výjimky.
Postupně se podíváme na všechny výše uvedené postupy.
Ošetření výjimky propagací
Tento postup je poměrně jednoduchý, výjimku neošetřujeme v místě, kde vznikla, její zpracování předáváme do nadřízené úrovně. Hierarchie předávání je následující: metoda->main->JVM. Pokud výjimku neošetříme před úrovní JVM, dojde k automatickému ukončení programu a zobrazení informace o chybě. Tento přístup je často používán, pokud provádíme nějakou operaci v cyklu, a nechceme opakovaně chybu řešit v těle cyklu. Uživatele tedy neinformujeme 50x o tom, že k chybě došlo, předáme tuto informaci při prvním výskytu metodě main() a zde rozhodneme o dalším běhu programu. V deklarace hlavičky metody použijeme klíčové slovo throws s identifkátorem výjimky, kterou chceme ošetřit.throws typ_vyjimky;
Podívejme se na následující příklad, se kterým jsme se již seznámili v části věnované formátovanému vstupu. Vytvoříme třídu Nacti, realizující načítání řetězců z formátovaného vstupu a jejich konverzi na číslo typu double.
public class Nacti
{
private byte [] pole;
public double getDouble() throws IOException
{
pole=new byte[128];
System.in.read(pole);
String ret=new String(pole);
ret=ret.trim();
double cislo=Double.valueOf(ret).doubleValue();
return cislo;
}
public static void main(String [] args) throws IOException
{
Nacti n=new Nacti();
double cislo=n.getDouble();
}
}
V hlavičce metody getDouble() přibyl kód
public double getDouble() throws IOException
sdělující, že metoda počítá, že by při jejím vykonávání mohlo dojít k výjimce IOException. Mohla by být způsobena špatně provedenými nebo přerušenými operacemi se standardním vstupem. Tato výjimka však , na rozdíl od NumberFormatException, neošetřuje konverzi řetězce, ve kterém by se kromě číslic vyskytly další znaky: písmena, speciální znaky, ... (např. uživatel místo 123 zadá 12#). Pokud by k takové výjimce došlo, nebude na této úrovni nijak řešena, bude odsunuta do nadřazené úrovně, tj. do metody main().
public static void main(String [] args) throws IOException
Zde není také nijak řešena, proto by program byl ukončen JVM. Vhodnější by bylo v tomto místě např. uživateli sdělit, že došlo k chybě vstupu (s tím se seznámíme v následující kapitole).
Který typ výjimky bude ošetřen? Upozorněme, že tímto způsobem je ošetřena pouze výjimka IOException a všechny výjimky od této třídy odvozené. Uplatňuje se zde princip, že potomek může zastoupit předka. Pokud by došlo k jiné výjimce, program se bude chovat, jako kdyby kód za throws neexistoval.
Pečlivého programátora by mohlo napadnout, že řešením by bylo ošetření všech chyb. Těch je však cca 30, takový program by se stal nepřehledným a zbytečně složitým. Vyplatí se proto strategie ošetřování pouze nejvíce bolavých míst programu. Jinou možností by bylo použít společného předka, třídu Exception.
public static void main(String [] args) throws Exception
V takovém případě však není možné jednoduše detekovat, k jaké výjimce došlo.
Ošetření výjimky metodou chráněných bloků
Tento postup umožňuje ošetřit výjimku v místě, kde vznikla. Využívá tzv. chráněného bloku, uvnitř kterého je uzavřen kód, při jehož vykonávání může dojít k výjimce. Chráněný blok je uveden příkazem try. Za ním následuje blok catch informující, jaký typ výjimky bude ošetřen. V případě výskytu výjimky v chráněném bloku try (typ výjimky musí být shodný s typem výjimky v části catch) dojde k jejímu zachycení a začne se vykonávat blok catch. Konstrukce try-catch může být doplněna i o nepovinný blok finally, který se provedevždy.
try
{
//chraneny blok
}
catch (typ vyjimky)
{
//osetreni vyjimky
}
finally
{
//provede se vzdy
}
Většinou se používá konstrukce try-catch, blok finally je využíván ve specifckých případech (např. při práci se soubory). Pokusme se upravit předchozí příklad tak, aby v okamžiku vzniku výjimky došlo k jejímu ošetření v bloku catch.
public class Nacti
{
private byte [] pole;
public double getDouble()
{
try
{
pole=new byte[128];
System.in.read(pole);
String ret=new String(pole);
ret=ret.trim();
double cislo=Double.valueOf(ret).doubleValue();
return cislo;
}
catch (IOException e)
{
System.out.prinln(Chyba pri zadavani udaju);
return 0;
}
}
public static void main(String [] args)
{
Nacti n=new Nacti();
double cislo=n.getDouble();
}
}
Pokud dojde při operacích se standardním vstupem k výjimce typu k výjimce IOException, je ošetřena v bloku catch. Tímto způsobem lze odchytit pouze výše uvedenou výjimku a výjimky od této třídy odvozené. Upozorněme, že opět nebude odchycena případná výjimka vzniklá konverzí String na double.
Autor: Filip Koval