Java: руководство для начинающих
Шрифт:
Рассмотрим в качестве примера следующую программу //В операторах catch исключения типа подкласса должны // предшествовать исключениям типа суперкласса, class ExcDemo5 { public static void main(String args[]) { // Здесь массив numer длиннее массива denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; icnumer.length; i++) { try { System.out.println(numer[i] + " / " + denom[i] + " is " + numer[i]/denom[i]); } // Перехват исключения от подкласса. catch (ArraylndexOutOfBoundsException exc) { System.out.println("No matching element found."); } // Перехват исключения от суперкласса. catch (Throwable exc) { System.out.println("Some exception occurred."); } } } }
Ниже
В данном случае оператор catch (Throwable) перехватывает все исключения, кроме ArraylndexOutOfBoundsException. Соблюдение правильного порядка следования операторов catch приобретает особое значение в том случае, когда исключения генерируются в самой программе. Вложенные блоки try
Блоки try могут быть вложенными друг в друга. Исключение, возникшее во внутреннем блоке try и не перехваченное связанным с ним блоком catch, распростра¬няется далее во внешний блок try и обрабатывается связанным с ним блоком catch. Такой порядок обработки исключений демонстрируется в приведенном ниже примере программы, где исключение ArraylndexOutOfBoundsException не перехватывается во внутреннем блоке catch, но обрабатывается во внешнем. // Применение вложенных блоков try. class NestTrys { public static void main(String args[]) { // Массив numer длиннее, чем массив denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; // Вложенные блоки try. try { // Внешний блок try. for(int i=0; i<numer.length; i++) { try { // Внутренний блок try. System.out.println(numer[i] + " / " + denom[i] + " is " + numer[i]/denom[i]) ; } catch (ArithmeticException exc) { // перехватить исключение System.out.println("Can't divide by Zero!"); } } } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("No matching element found."); System.out.println("Fatal error - program terminated."); } } }
Выполнение этой программы может дать, например, следующий результат: 4 / 2 is 2 Can't divide by Zero! 16 / 4 is 4 32 / 4 is 8 Can't divide by Zero! 128 / 8 is 16 No matching element found. Fatal error - program terminated.
В данном примере исключение, которое может быть обработано во внутреннем блоке try (в данном случае ошибка деления на нуль), не мешает дальнейшему выполнению программы. А вот ошибка превышения границ массива перехватывается во внешнем блоке try, что приводит к аварийному завершению программы.
Ситуация, продемонстрированная в предыдущем примере, является не единственной причиной для применения вложенных блоков try, хотя она встречается очень часто. В этом случае вложенные блоки try помогают по-разному обрабатывать разные типы ошибок. Одни ошибки невозможно устранить, а для других достаточно предусмотреть сравнительно простые действия. Внешний блок try чаще всего используется для перехвата критических ошибок, а менее серьезные ошибки обрабатываются во внутреннем блоке try. Генерирование исключений
В предыдущих примерах программ обрабатывались исключения, автоматически генерируемые виртуальной машиной Java. Но генерировать исключения можно и вручную, используя для этого оператор throw. Ниже приведена общая форма этого оператора. throw объект_исключения;
где объект_исключения должен быть объектом класса, производного от класса Throwable.
Ниже приведен пример программы, демонстрирующий применение оператора throw. В этой программе исключение ArithmeticException генерируется вручную. // Генерирование исключения вручную, class ThrowDemo { public static void main(String args[]) { try { System.out.println("Before throw."); // Генерирование исключения. throw new ArithmeticException ; } catch (ArithmeticException exc) { // перехватить исключение System.out.println("Exception caught."); } System.out.println("After try/catch block."); } }
Выполнение этой программы дает следующий результат: Before throw. Exception caught. After try/catch block. `
Обратите внимание на то, что исключение ArithmeticException генерируется с помощью ключевого слова new в операторе throw. Дело в том, что оператор throw генерирует исключение в виде объекта. Поэтому после ключевого слова throw недостаточно указать только тип исключения, нужно еще создать объект для этой цели. Повторное генерирование исключений
Исключение, перехваченное блоком catch, может быть повторно сгенерировано для обработки другим аналогичным блоком. Чаще всего повторное генерирование исключений применяется с целью предоставить разным обработчикам доступ к исключению. Так, например, повторное генерирование имеет смысл в том случае, если один обработчик оперирует одним свойством исключения, а другой обработчик ориентирован на другое его свойство. Повторно сгенерированное исключение не может быть перехвачено тем же самым блоком catch. Оно распространяется в другие блоки catch.
Ниже приведен пример программы, демонстрирующий повторное генерирование исключений. //•Повторное генерирование исключений, class Rethrow { public static void genException { // Массив numer длиннее маесивв denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; i<numer.length; i++) { try { System.out.println(numer[i] + " / " + denom[i] + " is " + numer[i]/denom[i]); } catch (ArithmeticException exc) { // перехватить исключение System.out.println("Can11 divide by Zero!"); } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("No matching element found."); throw exc; // Повторное генерирование исключения. } } } } class RethrowDemo { public static void main(String args[]) { try { Rethrow.genException; } catch(ArraylndexOutOfBoundsException exc) { // Перехват повторно сгенерированного включения. System.out.println("Fatal error - " + "program terminated."); } } }
В данной программе ошибка деления на нуль обрабатывается локально в методе genException , а при попытке обращения за границы массива исключение генерируется повторно. На этот раз оно перехватывается в методе main . Подробнее о классе Throwable
В приведенных до сих примерах программ только перехватывались исключения, но не выполнялось никаких действий над представляющими их объектами. В выражении оператора catch указываются тип исключения и параметр, принимающий объект исключения. А поскольку все исключения представлены подклассами, производными от класса Throwable, то они поддерживают методы, определенные в этом классе. Некоторые наиболее употребительные методы из класса Throwable приведены в табл. 9.1.
Таблица 9.1. Наиболее употребительные методы из класса Throwable Метод Описание Throwable filllnStackTrace Возвращает объект типа Throwable, содержащий полную трассировку стека исключений. Этот объект пригоден для повторного генерирования исключений String getLocalizedMessage Возвращает описание исключения, локализованное по региональным стандартам String getMessage Возвращает описание исключения void printStackTrace Выводит трассировку стека исключений void printStackTrace(PrintStream stream) Выводит трассировку стека исключений в указанный поток void printStackTrace(PrintWriter stream) Направляет трассировку стека исключений в указанный поток String toString Возвращает объект типа String, содержащий полное описание исключения. Этот метод вызывается из метода println при выводе объекта типа Throwable