* Хвърляне на изключения
Публикувано на 24 септември 2009 в раздел ПИК3 Java.
Понякога е удачно да пишем методи, които вместо да обработват сами изключенията на операторите вътре в тях, да прехвърлят изключенията на извикващите ги методи. Това е нещо като "прехвърляне на отговорността". Такава функционалност се получава чрез оператора "throw". Ето един тривиален пример - метод, който отпечатва съдържанието на файл на екрана:
public static void showFileContents(String filename) throws java.io.FileNotFoundException, java.io.IOException { java.io.BufferedReader in = new java.io.BufferedReader( new java.io.FileReader(filename)); int readbyte; while ((readbyte = in.read()) != -1) { System.out.print((char)readbyte); } in.close(); } public static void main(String[] args) { try{ showFileContents("input.txt"); } catch (java.io.FileNotFoundException e){ System.err.println("File not found"); } catch (java.io.IOException e){ System.err.println("IO error has occured"); } }
Виждате, че в метод showFileContents ние никъде не се погрижихме за търсене на изключения. Ако методите използвани от BufferedReader достигнат до FileNotFoundException или IOException - те просто ги прехвърлят към метода main.
Изключенията обаче могат да бъдат прехвърляни и през няколко нива. Например:
public static java.io.BufferedReader openFile(String filename) throws java.io.FileNotFoundException, java.io.IOException{ java.io.BufferedReader in = new java.io.BufferedReader( new java.io.FileReader(filename)); return in; } public static void showFileContents(String filename) throws java.io.IOException { java.io.BufferedReader in = null; try{ in = openFile(filename); int readbyte; while ((readbyte = in.read()) != -1) { System.out.print((char)readbyte); } } catch(java.io.FileNotFoundException e){ System.err.println("File Not Found"); } finally{ try{ if (in!=null) in.close(); } catch (java.io.IOException e){} } } public static void main(String[] args) { try{ showFileContents("input.txt"); } catch (java.io.IOException e){ System.err.println("IO error has occured"); } }
От този пример виждаме, че ако в метод openFile възникне някаква грешка с отварянето на файл, то тя ще бъде прехвърлена към извикващия метод - showFileContents. Той от своя страна се грижи за обработката на FileNotFoundException, но не и за IOException. Така ако се получи IOЕxception (независимо дали в метод openFile или showFileContents) тя ще бъде хвърлена към метода main, който вече е длъжен да я обработи. Така получихме т.нар. "каскадно" обработване на грешка.
Предвидена е и още една възможност - самите ние да "хвърлим" изключение към викащия метод. Нека напишем метод, който получава като аргумент масив и число и дели всички елементи на масива на това число. При подадено число 0, то методът ще хвърли ArithmeticException:
public static void divArray(int[] arr, int divisor) throws java.lang.ArithmeticException{ if (divisor == 0) throw new java.lang.ArithmeticException("You divide by 0"); for (int i=0; i<arr.length; i++){ arr[i] /= divisor; } } public static void main(String[] args) { int[] arr = {1,3,6,0,9}; try{ divArray(arr, 0); } catch (java.lang.ArithmeticException e){ System.err.println(e.getMessage()); System.err.println("We will only print the original array:"); } for (int i: arr){ System.out.print(i+" "); } }
Специално сме удебелили една важна функционалност - методът "getMessage()". Виждате, че при създаването на изключението ние подадохме като параметър текст "You divide by 0". Когато прихващаме това изключение в метода main, то чрез методът "getMessage()" ние взимаме именно този текст и в случая го отпечатваме в стандартния поток за грешки. Изключенията имат такъв текст и по подразбиране, но по този начин е ясно, че можем да сме по-гъвкави.
След като знаем за тази функционалност, нека се върнем към "лошия пример" от предишна статия и да покажем как можем да я използваме:
// Izchisliava x ot a.x + b = 0 double a = 0; double b = 4; try{ if (a == 0){ if (b == 0) throw new java.lang.ArithmeticException("Vsiako x e reshenie"); else throw new java.lang.ArithmeticException("Niama reshenie"); } System.out.println("x = "+(-b/a)); } catch (java.lang.ArithmeticException e){ System.out.println(e.getMessage()); }
Естествено пак ще повторим казаното в предишната статия, че работата с изключения трябва максимално да се отбягва. Подобни примери могат да доведат само до загуба на производителност и нищо полезно. Затова използвайте и хвърляйте изключения само когато е необходимо! С този пример просто демонстрираме възможностите на throw и нищо друго.
Добави коментар