Текст книги "Java: руководство для начинающих (ЛП)"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 19 (всего у книги 36 страниц)
Глава 9 Обработка исключений
Основные навыки и понятия
Представление об иерархии исключений
Использование ключевых слов try и catch
Последствия неперехвата исключений
Применение нескольких операторов catch
Перехват исключений, генерируемых подклассами
Вложенные блоки try
Генерирование исключений
Представление о членах класса Throwable
Использование ключевого слова finally
Использование ключевого слова throws
Представление о исключениях, встроенные в Java
Создание специальных классов исключений
В этой главе речь пойдет об обработке исключительный ситуаций, или просто исключений. Исключение – это ошибка, возникающая в процессе выполнения программы. Используя подсистему обработки исключений Java, можно контролировать реакцию программы на появление ошибок в ходе ее выполнения. Средства обработки исключений в том или ином виде присутствуют практически во всех современных языках программирования. Можно смело утверждать, что в Java подобные инструментальные средства отличаются большей гибкостью, более понятны и удобны в употреблении по сравнению с большинством других языков программирования.
Преимущество обработки исключений заключается в том, что она автоматически предусматривает реакцию на многие ошибки, избавляя от необходимости писать вручную соответствующий код. Например, в некоторых старых языках программирования предусматривается возврат специального кода при возникновении ошибки в ходе выполнения метода. Этот код приходится проверять вручную при каждом вызове метода. Такой подход к обработке ошибок вручную трудоемок и чреват погрешностями. Обработка исключений упрощает этот процесс, давая возможность определять в программе блок кода, называемый обработчиком исключения и автоматически выполняющийся при возникновении ошибки. Это избавляет от необходимости проверять вручную, насколько удачно или неудачно была выполнена та или иная операция или вызов метода. Если возникнет ошибка, все необходимые действия по ее обработке выполнит обработчик исключений.
В Java определены стандартные исключения для наиболее часто встречающихся программных ошибок, в том числе деления на нуль или попытки открыть несуществующий файл. Для того чтобы обеспечить требуемую реакцию на конкретную ошибку, в программу следует включить соответствующий обработчик событий. Исключения широко применяются в библиотеке Java API. Иерархия исключений
В Java все исключения представлены отдельными классами. Все классы исключений являются потомками класса Throwable. Так, если в программе возникнет исключительная ситуация, будет сгенерирован объект класса, соответствующего определенному типу исключения. У класса Throwable имеются два непосредственных подкласса: Exception и Error. Исключения типа Error относятся к ошибкам, возникающим в виртуальной машине Java, а не в прикладной программе. Контролировать такие исключения невозможно, поэтому реакция на них в прикладной программе, как правило, не предусматривается. В связи с этим исключения данного типа не будут описываться в этой книге.
Ошибки, связанные с выполнением действий в программе, представлены отдельными подклассами, производными от класса Exception. К этой категории, в частности, относятся ошибки деления на нуль, выхода за границы массива и обращения к файлам. Подобные ошибки следует обрабатывать в самой программе. Важным подклассом, производным от Exception, является класс RuntimeException, который служит для представления различных видов ошибок, часто встречающихся при выполнении программ. Общее представление об обработке исключений
Для обработки исключений в Java предусмотрены пять ключевых слов: try, catch, throw, throws и finally. Они образуют единую подсистему, в которой использование одного ключевого слова почти всегда автоматически влечет за собой употребление другого. Каждое из упомянутых выше ключевых слов будет подробно рассмотрено далее в этой главе. Но прежде следует дать общее представление об их роли в процессе обработки исключений. Поэтому ниже поясняется вкратце, каким образом они действуют.
Операторы, в которых требуется отслеживать появление исключений, помещаются в блок try. Если в блоке try будет сгенерировано исключение, его можно перехватить и обработать нужным образом. Системные исключения генерируются автоматически. А для того чтобы сгенерировать исключение вручную, следует воспользоваться ключевым словом throw. Иногда возникает потребность обрабатывать исключения за пределами метода, в котором они возникают, и для этой цели служит ключевое слово throws. Если же некоторый фрагмент кода должен быть выполнен обязательно и независимо от того, возникнет исключение или нет, его следует поместить в блок finally. Использование ключевых слов try и catch
Основными языковыми средствами обработки исключений являются ключевые слова try и catch. Они используются совместно. Это означает, что нельзя указать ключевое слово catch в коде, не указав ключевое слово try. Ниже приведена общая форма записи блоков try/catch, предназначенных для обработки исключений. try { // Блок кода, в котором должны отслеживаться ошибки } catch (тип_исключения_1 объект_исключения) { // Обработчик исключения тип_исключения_1 ) catch (тип_исключения_2 объект_исключения) { // Обработчик исключения тип_исключения_2 }
В скобках, следующих за ключевым словом catch, указываются тип исключения и переменная, ссылающаяся на объект данного типа. Когда возникает исключение, оно перехватывается соответствующим оператором catch, обрабатывающим это исключение. Как следует из приведенной выше общей формы записи, с одним блоком try может быть связано несколько операторов catch. Тип исключения определяет, какой именно оператор catch будет выполняться. Так, если тип исключения соответствует типу оператора catch, то именно он и будет выполнен, а остальные операторы catch – пропущены. При перехвате исключения переменной, указанной в скобках после ключевого слова catch, присваивается ссылка на объект_исключения.
Следует иметь в виду, что если исключение не генерируется, блок try завершается обычным образом и ни один из его операторов catch не выполняется. Выполнение программы продолжается с первого оператора, следующего за последним оператором catch. Таким образом, операторы catch выполняются только при появлении исключения.
На заметку. В версии JDK 7 внедрена новая форма оператора try, поддерживающая автоматическое управления ресурсами и называемая оператором try с ресурсами. Более подробно она описывается в главе 10 при рассмотрении потоков ввода-вывода, в том числе и тех, что связаны с файлами, поскольку потоки ввода-вывода относятся к числу ресурсов, наиболее употребительных в прикладных программах. Простой пример обработки исключений
Рассмотрим простой пример, демонстрирующий перехват и обработку исключения. Как известно, попытка обратиться за границы массива приводит к ошибке, и виртуальная машина Java генерирует соответствующее исключение ArraylndexOutOf BoundsException. Ниже приведен код программы, в которой намеренно создаются условия для появления данного исключения, которое затем перехватывается. // Демонстрация обработки исключений, class ExcDemol { public static void main (String args[]) { int nums[] = new int[4]; // Создание блока try. try { System.out.println("Before exception is generated."); // Попытка обратиться за границы массива. nums[7] = 10; System.out.println("this won't be displayed"); } // Перехват исключения в связи с обращением за границы массива. catch (ArraylndexOutOfBoundsException exc) { System.out.println("Index out-of-bounds!"); } System.out.println("After catch statement."); } }
Результат выполнения данной программы выглядит следующим образом: Before exception is generated. Index out-of-bounds! After catch statement.
Несмотря на всю простоту данного примера программы, он наглядно демонстрирует несколько важных особенностей обработки исключений. Во-первых, код, подлежащий проверке на наличие ошибок, помещается в блок try. И во-вторых, когда возникает исключение (в данном случае это происходит при попытке обратиться за границы массива), выполнение блока try прерывается и управление получает блок catch. Следовательно, явного обращения к блоку catch не происходит, но переход к нему осуществляется лишь при определенном условии, возникающем в ходе выполнения программы. Так, оператор вызова метода println (), следующий за выражением, в котором происходит обращение к несуществующему элементу массива, вообще не выполняется. По завершении блока catch выполнение программы продолжается с оператора, следующего за этим блоком. Таким образом, обработчик исключений предназначен для устранения программных ошибок, приводящих к исключительным ситуациям, а также для обеспечения нормального продолжения исполняемой программы.
Как упоминалось выше, если в блоке try не возникнут исключения, операторы в блоке catch не получат управление и выполнение программы продолжится после блока catch. Для того чтобы убедиться в этом, измените в предыдущей программе строку кода nums[7] = 10;
на следующую строку кода: nums[0] = 10;
Теперь исключение не возникнет и блок catch не выполнится.
Важно понимать, что исключения отслеживаются во всем коде в блоке try. К их числу относятся исключения, которые могут быть сгенерированы методом, вызываемым из блока try. Исключения, возникающие в вызываемом методе, перехватываются операторами в блоке catch, связанном с блоком try. Правда, это произойдет лишь в том случае, если метод не обрабатывает исключения самостоятельно. Рассмотрим в качестве примера следующую программу: /* Исключение может быть сгенерировано одним методом, а перехвачено другим. */ class ExcTest { // сгенерировать исключение static void genException() { int nums[] = new int[4]; System.out.println("Before exception is generated."); // Здесь генерируется исключение в связи с // обращением за границы массива. nums[7] = 10; System.out.println("this won't be displayed"); } } class ExcDemo2 { public static void main(String args[]) { try { ExcTest.genException() ; } //А здесь исключение перехватывается. catch (ArraylndexOutOfBoundsException exc) { System.out.println("Index out-of-bounds!"); } System.out.println("After catch statement."); } }
Выполнение этой версии программы дает такой же результат, как и при выполнении ее предыдущей версии. Этот результат приведен ниже. Before exception is generated. Index out-of-bounds! After catch statement.
Метод genException () вызывается из блока try, и поэтому генерируемое, но не перехватываемое в нем исключение перехватывается далее в блоке catch в методе main (). Если бы метод genException () сам перехватывал исключение, оно вообще не дошло бы до метода main (). Последствия неперехвата исключений
Перехват стандартного исключения Java, продемонстрированный в предыдущем примере, позволяет предотвратить завершение программы вследствие ошибки. Генерируемое исключение должно быть перехвачено и обработано. Если исключение не обрабатывается в программе, оно будет обработано виртуальной машиной Java. Но дело в том, что по умолчанию виртуальная машина Java аварийно завершает программу, выводя сообщение об ошибке и трассировку стека исключений. Допустим, в предыдущем примере попытка обращения за границы массива не отслеживается и исключение не перехватывается, как показано ниже. // Обработка ошибки средствами виртуальной машины Java, class NotHandled { public static void main(String args[]) { int nums[] = new int[4]; System.out.println("Before exception is generated."); // Попытка обращения за границы массива, nums[7] = 10; } }
При появлении ошибки, связанной с обращением за границы массива, выполнение программы прекращается и выводится следующее сообщение: Exception in thread "main" java.lang.ArraylndexOutOfBoundsException: 7 at NotHandled.main(NotHandled.java:9)
Оно полезно на этапе отладки, но пользователям программы эта информация вряд ли нужна. Именно поэтому очень важно, чтобы программы обрабатывали исключения самостоятельно и не поручали эту задачу виртуальной машине Java.
Как упоминалось выше, тип исключения должен соответствовать типу, указанному в операторе catch. В противном случае исключение не будет перехвачено. Так, в приведенном ниже примере программы делается попытка перехватить исключение, связанное с обращением за границы массива, с помощью оператора catch, в котором указан тип ArithmeticException еще одного встроенного в Java исключения. При неправильном обращении к массиву будет сгенерировано исключение ArraylndexOutOfBoundsException, не соответствующее типу, указанному в операторе catch. В результате программа будет завершена аварийно. // Эта программа не будет работать нормально! class ExcTypeMismatch { public static void main(String args[]) { int nums[] = new int[4]; try { System.out.println("Before exception is generated."); // При выполнении следующего оператора возникает // исключение ArraylndexOutOfBoundsException nums[7] = 10; System.out.println("this won’t be displayed"); } /* Исключение, связанное с обращением за границы массива, нельзя обработать с помощью оператора catch, в котором указан тип исключения ArithmeticException. */ catch (ArithmeticException exc) { System.out.println("Index out-of-bounds!"); } System.out.println("After catch statement."); } }
Ниже приведен результат выполнения данной программы. 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 Результат выполнения данной программы выглядит следующим образом: 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 Данный пример демонстрирует еще одну важную особенность: обработанное исключение удаляется из системы. Иными словами, на каждом шаге цикла блок 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 Выполнение этой программы дает следующий результат: 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. 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 2 Some exception occurred. 16 / 4 is 4 32 / 4 is 8 Some exception occurred. 128 / 8 is 16 No 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 Выполнение этой программы может дать, например, следующий результат: 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 В данной программе ошибка деления на нуль обрабатывается локально в методе 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 Среди методов, определенных в классе Throwable, наибольший интерес представляют методы pr intStackTrace () и toString(). С помощью метода printStackTrace () можно вывести стандартное сообщение об ошибке и запись последовательности вызовов методов, которые привели к возникновению исключения, А метод toString () позволяет получить стандартное сообщение об ошибке. Этот метод также вызывается в том случае, когда объект исключения передается в качестве параметра методу println (). Применение этих методов демонстрируется в следующем примере программы: // Применение методов из класса Throwable. class ExcTest { static void genException() { int nums[] = new int[4]; System.out.println("Before exception is generated."); // сгенерировать исключение в связи с попыткой // обращения за границы массива nums[7] = 10; System.out.println("this won't be displayed"); } } class UseThrowableMethods { public static void main(String args[]) { try { ExcTest.genException() ; } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("Standard message is: "); System.out.println(exc) ; System.out.println("nStack trace: "); exc.printStackTrace(); } System.out.println("After catch statement."); } } Результат выполнения данной программы выглядит следующим образом: Before exception is generated. Standard message is: java.lang.ArraylndexOutOfBoundsException: 7 Stack trace: java.lang.ArraylndexOutOfBoundsException: 7 at ExcTest.genException(UseThrowableMethods.java:10) at UseThrowableMethods.main(UseThrowableMethods.java:19) After catch statement. Использование ключевого слова finally Иногда требуется определить кодовый блок, который должен выполняться по завершении блока try/catch. Допустим, в процессе работы программы возникло исключение, требующее ее преждевременного завершения. Но в программе открыт файл или установлено сетевое соединение, а следовательно, файл нужно закрыть, а соединение разорвать. Для выполнения подобных операций нормального завершения программы удобно воспользоваться ключевым словом finally. Для того чтобы определить код, который должен выполняться по завершении блока try/catch, нужно указать блок finally в конце последовательности операторов try/catch. Ниже приведена общая форма записи блока try/catch вместе с блоком finally. try { // Блок кода, в котором отслеживаются ошибки. } catch (тип_исключения_1 объект_исключения) { // Обработчик исключения тип_исключения_1 ) catch (тип_исключения_2 объект_исключения) { // Обработчик исключения тип_исключения_2 } //. . . finally { // Код блока finally } Блок finally выполняется всегда по завершении блока try/catch независимо от того, какое именно условие к этому привело. Следовательно, блок finally получит управление как при нормальной работе программы, так и при возникновении ошибки. Более того, он будет вызван даже в том случае, если в блоке try или в одном из блоков catch будет присутствовать оператор return для немедленного возврата из метода. Ниже приведен краткий пример программы, демонстрирующий применение блока finally. // Применение блока finally, class UseFinally { public static void genException(int what) { int t; int nums[] = new int[2]; System.out.println("Receiving " + what); try { switch(what) { case 0: t = 10 / what; // сгенерировать ошибку деления на нуль break; case 1: nums[4] = 4; // сгенерировать ошибку обращения к массиву break; case 2: return; // возвратиться из блока try } } catch (ArithmeticException exc) { // перехватить исключение System.out.println("Can1t divide by Zero!"); return; // возвратиться из блока catch } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("No matching element found."); } // Этот блок выполняется независимо от того, каким // образом завершается блок try/catch. finally { System.out.println("Leaving try."); } } } class FinallyDemo { public static void main(String args[]) { for(int i=0; i < 3; i++) { UseFinally.genException(i); System.out.println() ; } } } В результате выполнения данной программы получается следующий результат: Receiving О Can't divide by Zero! Leaving try. Receiving 1 No matching element found. Leaving try. Receiving 2 Leaving try. Нетрудно заметить, что блок finally выполняется независимо от того, каким об¬ разом завершается блок try/catch. Использование ключевого слова throws Иногда исключения нецелесообразно обрабатывать в том методе, в котором они возникают. В таком случае их следует указывать с помощью ключевого слова throws. Ниже приведена общая форма объявления метода, в котором присутствует ключевое слово throws. возвращаемый_тип имя_метода(список_параметров) throws список_исключений { // Тело метода }