Назад | Содержание | Вперед
Все ошибки в программах делятся на два вида: ошибки времени трансляции (интерпретации или компиляции) и ошибки времени выполнения (run-time error). Ошибки времени выполнения могут возникать по ходу выполнения программы не всегда, а только в случае выполнения каких-либо условий (например, при обращении в ноль некоторого вычисляемого выражения и использовании его в качестве делителя возникает ошибка времени выполнения «деление на нуль», при удалении файла, к которому обращается программа, возникает ошибка времени выполнения «файл не найден»). Сложность поиска и исправления таких ошибок заключается в том, что компилятор не может предсказать их появление. Поэтому логично было бы обрабатывать такие ошибки (они называются исключениями) непосредственно по ходу выполнения программы в случае их возникновения. Под обработкой ошибки времени выполнения предусматривается выдача на экран сообщения о произошедшей ошибке, выполнение каких-либо действий по устранению ошибки, продолжение выполнения программы если это возможно или ее корректное завершение в противном случае.
В языке Java реализован объектно-ориентированный подход к обработке исключений. Исключение в Java — это объект, который описывает исключительное состояние, возникшее в каком-либо участке программного кода. При возникновении исключения порождается объект, связанный с данным исключением. Соответственно, этот объект является объектом некоторого класса. Т.е. существует некоторое множество классов Java, которые являются классами исключительных ситуаций. Так, FileNotFoundException - это класс. Имя класса исключительной ситуации и имя исключения употребляются как синонимы. Т.е., каждая исключительная ситуация имеет свое имя и это имя класса исключительной ситуации.
Объект, порождаемый при возникновении исключения, служит для хранения информации о возникшей исключительной ситуации (точка возникновения, описание и т.п.). Используя методы этого объекта можно, например, вывести на экран или в файл информацию о возникшем исключении.
Обработка исключений в Java управляется с помощью 5 ключевых слов – try, catch, throw, throws, finally. Опишем кратко, как они работают. Программные операторы, которые нужно контролировать на предмет возникновения исключений содержатся в блоке try{ }. Если в блоке try возникает исключение, говорят, что оно выброшено (thrown) этим блоком. Код может перехватить данное исключение и обработать его в блоке catch{ }. Исключения, генерируемые исполнительной системой Java, возникают выбрасываются автоматически. Для программной генерации исключения используется оператор throw. Любое исключение, которое может быть выброшено из метода, следует определять с помощью ключевого слова throws, размещаемого в заголовке определения метода. Если перед выходом из блока try обязательно (вне зависимости от возникновения исключений) должны быть выполнены некоторые действия (например, освобождены захваченные системные ресурсы), то эти действия необходимо поместить в блок finally{ }.
В заголовке блока catch, указывается имя класса исключения, для обработки которого предназначен этот блок. Блок будет срабатывать только при возникновении данного исключения или исключения, порожденного от данного (напомним, исключения - это классы, т.е. для них допустимо наследование классов). Имя exOb в заголовке catch-блока – это произвольное имя. Оно служит для именования объекта-исключения и с его помощью можно извлечь информацию о возникшем исключении. Блоков catch в данном try-catch-блоке может быть несколько – каждый для своего исключения.
JVM поддерживает стек вызовов, содержащий список методов, вызванных данным потоком, начиная с первого вызванного метода и заканчивая текущим методом. Стек вызовов показывает путь вызова методов, произведенных потоком для достижения текущего. Допустим, метод main() вызвал метод A, метода А вызвал метод B, который, в свою очередь, вызвал метод C.
Тогда во время выполнения метода C стек вызовов будет выглядеть следующим образом:
C
B
A
main()
При нормальном завершении метода его фрейм выталкивается из стека и фрейм стека, находящегося под ним, становится текущим, то есть выполняемым в настоящий момент методом.
В стандартной библиотеке Java существует развитая иерархия классов исключительных ситуаций. Это не произвольные классы Java. Они обладают своими особенностями и строятся по определенным правилам. Правила построения классов исключительных ситуаций базируются на аппарате наследования и состоят в том, что классы исключительных ситуаций должны быть наследниками определенных классов стандартной библиотеки Java.
В вершине иерархии классов исключений стоит класс Throwable. Это базовый класс для всех типов исключительных ситуаций. Каждый из типов исключений является подклассом класса Throwable. Непосредственными наследниками Throwable являются два подкласса, которые разделяют классы исключений на две различные ветви. Во главе первой ветви находится класс Exception, используемый для описания исключительных ситуаций, которые должны перехватываться программным кодом пользователя. Созданные в программе собственные типы исключений должны быть наследниками класса Exception (или его потомков). Другая ветвь дерева подклассов Throwable возглавляется классом Error, который предназначен для описания исключительных ситуаций, вызванных серьезными сбоями в работе виртуальной машины Java. Если возникла исключительная ситуация типа Error, то возможность продолжения работы программы маловероятна, поэтому перехватывать исключения типа Error в программе не нужно. Пример исключительной ситуации типа Error – переполнение стека.
Все исключения порождаемые от класса Exception являются “checked”, т.е. должны быть обработаны в программе и это условие проверяется (checked) компилятором. При этом у класса Exception имеется важный подкласс RuntimeException. Исключения, порождаемые от этого класса являются “unchecked”, т.е. компилятор не проверяет, обработаны ли они (что не отменяет необходимости их обработки с точки зрения корректности поведения программы). Исключения, порожденные от Error, также являются unchecked.
До сих пор все исключения в ходе выполнения программы выбрасывались исполнительной системой Java. Однако в ходе выполнения программы могут возникать ошибочные ситуации, которые не являются таковыми с точки зрения исполнительной системы, однако противоречат логике, заложенной в программу. В этом случае можно выбрасывать исключения явным образом. Для этого используется оператор throw.
TrowableObject должен быть объектом класса Throwable или его подклассов. Такой объект можно либо получить как параметр оператора catch, либо создать с помощью оператора new. При достижении этого оператора нормальное выполнение кода немедленно прекращается, так что следующий за ним оператор не выполняется. Ближайший окружающий блок try проверяется на наличие соответствующего возбужденному исключению обработчика catch. Если такой отыщется, управление передается ему. Если нет, проверяется следующий из вложенных операторов try, и так до тех пор пока либо не будет найден подходящий раздел catch, либо не будет вызван обработчик исключений исполняющей системы Java.
Все встроенные типы исключений имеют два конструктора – один без параметра, а другой – со строчным параметром, определяющим строку, описывающую исключение. Таким образом, для создания исключений с помощью оператора new можно использовать одну из двух форм:
throw new <ExceptionClassName>();
throw new <ExceptionClassName>(“…”);
Исключения, которые порождены от Exception, но не от RuntimeException, могут быть сгенерированы только явно операцией throw. При этом если метод может выбрасывать одно из таких исключений, то должно выполняться одно из двух условий: либо для такого исключения должен быть catch-обработчик, либо в заголовке такого метода должна стоять конструкция
throws <ExceptionClassName1> [,<ExceptionClassName2>,…]
В свою очередь, вызов метода, в описании которого стоит " throws ... ", тоже должен находиться либо внутри try-catch-блока, либо внутри метода с конструкцией " throws ... " в его заголовке. Таким образом, где-то в программе любое возможное исключение типа Exception обязано быть перехвачено и у компилятора появляется возможность это проконтролировать.
Большинство библиотечных методов определено с ключевым словом throws, это сделано специально чтобы оставить конкретную обработку исключения на усмотрение вашего приложения. Вызов таких методов приводит к необходимости учитывать Catch or Specify requirement.
Назад | Содержание | Вперед