Ниже приведен результат выполнения данной программы.Before exception is generated.Exception in thread "main" java.lang.ArraylndexOutOfBoundsException: 7 at ExcTypeMismatch.main(ExcTypeMismatch.java:10)
Нетрудно заметить, что оператор catch, в котором указан тип исключения ArithmeticException, не может перехватить исключение ArraylndexOutOfBoundsException.Обработка исключений — изящный способ устранения программных ошибок
Одно из главных преимуществ обработки исключений заключается в том, что она позволяет вовремя отреагировать на ошибку в программе и затем продолжить ее выполнение. В качестве примера рассмотрим еще одну программу, в которой элементы одного массива делятся на элементы другого. Если при этом происходит деление на нуль, то генерируется исключение ArithmeticException. Обработка подобного исключения заключается в том, что программа уведомляет об ошибке и затем продолжает свое выполнение. Таким образом, попытка деления на нуль не приведет к аварийному завершению программы из-за ошибки при ее выполнении. Вместо этого ошибка обрабатывается изящно, не прерывая выполнение программы.// Изящная обработка исключения и продолжение выполнения программы,class ExcDemo3 { public static void main(String args[]) { int numer[] = { 4, 8, 16, 32, 64, 128 }; 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("Can't divide by Zero!"); } } }}
Результат выполнения данной программы выглядит следующим образом:4 / 2 is 2Can't divide by Zero!16/ 4 is 432 / 4 is 8Can't divide by Zero!128 / 8 is 16
Данный пример демонстрирует еще одну важную особенность: обработанное исключение удаляется из системы. Иными словами, на каждом шаге цикла блок try выполняется в программе сызнова, а все возникшие ранее исключения считаются обработанными. Благодаря этому в программе могут обрабатываться повторяющиеся ошибки.Применение нескольких операторов catch
Как пояснялось ранее, с блоком try можно связать несколько операторов catch. Обычно разработчики так и поступают на практике. Каждый из операторов catch должен перехватывать отдельный тип исключений. Например, в приведенной ниже программе обрабатываются как исключения, связанные с обращением за границы массива, так и ошибки деления на нуль.// Применение нескольких операторов catch. 'class ExcDemo4 { 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; i<numer.length; i++) { try { System.out.println(numer[i] + " / " + denom[i] + " is " + numer[i]/denom[i]); } // За блоком try следует несколько блоков catch подряд, catch (ArithmeticException exc) { // перехватить исключение System.out.println("Can't divide by Zero!"); } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("No matching element found."); } } }}
Выполнение этой программы дает следующий результат:4 / 2 is 2Can't divide by Zero!16 / 4 is 432 / 4 is 8Can't divide by Zero!128 / 8 is 16No matching element found.No matching element found.
Как подтверждает приведенный выше результат выполнения программы, в каждом блоке оператора catch обрабатывается свой тип исключения.
Вообще говоря, выражения с операторами catch проверяются в том порядке, в котором они встречаются в программе. И выполняется лишь тот из них, который соответствует типу возникшего исключения. А остальные блоки операторов catch просто игнорируются.Перехват исключений, генерируемых подклассами
подклассамиВ отношении подклассов следует отметить еще одну интересную особенность применения нескольких операторов catch: условие перехвата исключений для суперкласса будет справедливо и для любых его подклассов. Например, класс Throwable является суперклассом для всех исключений, поэтому для перехвата всех возможных исключений в операторах catch следует указывать тип Throwable. Если же требуется перехватывать исключения типа суперкласса и типа подкласса, то в блоке операторов первым должен быть указан тип исключения, генерируемого подклассом. В противном случае вместе с исключением типа суперкласса будут перехвачены и все исключения производных от него классов. Это правило соблюдается автоматически, и если указать первым тип исключения, генерируемого суперклассом, то будет создан недостижимый код, поскольку условие перехвата исключения, генерируемого подклассом, никогда не будет выполнено. А ведь недостижимый код в 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."); } } }}
Ниже приведен результат выполнения данной программы.4 / 2 is 2Some exception occurred.16 / 4 is 432 / 4 is 8Some exception occurred.128 / 8 is 16No matching element found.No matching element found.
В данном случае оператор 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 2Can't divide by Zero!16 / 4 is 432 / 4 is 8Can't divide by Zero!128 / 8 is 16No matching element found.Fatal error - program terminated.
В данном примере исключение, которое может быть обработано во внутреннем блоке try (в данном случае ошибка деления на нуль), не мешает дальнейшему выполнению программы. А вот ошибка превышения границ массива перехватывается во внешнем блоке try, что приводит к аварийному завершению программы.
Ситуация, продемонстрированная в предыдущем примере, является не единственной причиной для применения вложенных блоков try, хотя она встречается очень часто. В этом случае вложенные блоки try помогают по-разному обрабатывать разные типы ошибок. Одни ошибки невозможно устранить, а для других достаточно предусмотреть сравнительно простые действия. Внешний блок try чаще всего используется для перехвата критических ошибок, а менее серьезные ошибки обрабатываются во внутреннем блоке try.Генерирование исключений