Основными языковыми средствами обработки исключений являются ключевые слова 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."); }}