Обработка исключительных ситуаций Андрей Дмитриев 2008
Что должно произойти при исполнении этой программы? class SimpleMistake { public static void main(String args[]) { System.out.println(1/0); }
Программа Введение Исключения и ошибки Проверяемые и непроверяемые исключения Блок try-catch-finally Оператор throw Зарезервированное слово throws Некоторые типы исключений
Что такое Исключение? Исключение в Java это объект, который описывает исключительное состояние, возникшее в каком-либо участке программного кода Когда возникает исключительное состояние, создается объект класса Exception Этот объект пересылается в метод, обрабатывающий данный тип исключительной ситуации По « следам » стека программы можно найти данный метод – и причину ошибки
Метод, в котором возникла ошибка Метод, не обрабаты- вающий исключение Метод, обрабаты- вающий исключение Схема возникновения и обработки исключений main Метод, в котором возникла ошибка Метод, не обрабаты- вающий исключение Метод, обрабаты- вающий исключение main Вызов метода Ищет подходящий обработчик Ищет подходящий обработчик Вызов метода Вызов метода Генерирует исключение Передает дальше Обрабатывает исключение
Что исключение поможет найти? Тип исключения указывает на причину его возникновения Стек вызовов позволяет отследить путь, по которому был достигнут проблемный код Стандартный обработчик выдает номер строки кода, в котором произошло исключение В разработке можно использовать средства отладка (debug) точка остановка выполнения программы (breakpoint)
Возникновение исключения class SimpleMistake { public static void main(String args[]) { int d = 0; int a = 42 / d; } Совершаем преднамеренную ошибку – делим на ноль
Обработка исключения class SimpleMistake{ public static void main(String args[]){ try{ int d = 0; //выполнится int a = 42 / d; int z = a + d; //не выполнится } catch (ArithmeticException e) { System.out.println(«Деление на ноль"); } Ловим свою ошибку и выводим информацию на консоль
Как действует связка try-catch try { doSomethingDangerous(); //опасный метод } catch (CatchedExceptionType e) { treatDanger(); //обработка исключения } //CatchedExceptionType – класс, к которому принадлежит исключение e } catch (...) { }
Виды исключений Проверяемое FileNotFoundException, IOException, … После такой ситуации зачастую требуется восстановление состояния программы Обязательны для описания при определении метода Ошибка Класс java.lang.Error и его наследники Исключение времени исполнения Оно же непроверяемое RuntimeException и все наследники Восстановление после таких ситуаций обычно не производится
Примеры исключений ArithmeticExceptionОшибка при вычислениях – например, деление на 0. ArrayIndexOutOfBoundsExceptionВыход за пределы массива. FileNotFoundExceptionЕсли не обнаружен запрошенный файл. IOExceptionЛюбое исключение в системе ввода/вывода; включает предыдущее. OutOfMemoryErrorРеакция на нехватку памяти. VirtualMachineErrorОшибка внутри вируальной машины Java. AWTErrorОшибка при работе графического интерфейса.
Иерархия Throwable объектов Exception Throwable IOException Serializable Error Assertion Error OutOfMemory Error VirtualMachine Error Runtime Exception Arithmetic Exception SQLException IndexOutOf BoundsException
Требования к коду Если метод вызывает проверяемое исключение, то он должен > либо обработать его > либо передать исключение выше по стеку вызова Неудовлетворяющий этому правилу код не компилируется
Каскад обработчиков class MultiCatch { public static void main (String args[]) { try { riskyMethod(); } catch (ArithmeticException e) { tryToHandleArithmetic(); } catch(ArrayIndexOutOfBoundsException e) { tryToHandleIndex(); } Иногда одного обработчика недостаточно – создаем несколько, на разные типы исключений
Вложенные блоки class LevelNest{ public static void main(String args[]) { try { //может бросить арифметическое исключение doSomePreparation(); //тоже может бросить, но наружу //оно не передано не будет - см. следующий слайд. doCalculation (); } сatch (ArithmeticException e) { tryToHandle(); } Также можно вкладывать один блок try-catch в другой Число вложений ограничено реализацией JVM
Вложенные блоки (cont.) public static void doCalculation(){ try { riskyCode(); } catch(ArrayIndexOutOfBoundsException e) { tryToHandle(); } Этот метод сам обрабатывает свое же исключение, поэтому наружу исключение не передается
Явно брошенное исключение class ThrowDemo { void riskyMethod(int value) { try { //какие-то действия if (value == 1){ //бросаем исключение throw new IllegalArgumentException (Cant be 1"); } }catch (IllegalArgumentException e) { prepareToClose(); //передача исключения выше throw e; } Новое исключение создается посредством вызова конструктора Конструктор принимает строку, описывающую причину исключения Генерирование исключения происходит с помощью оператора throw
Описание исключений class ThrowsDemo { static void riskyMethod() throws IllegalAccessException { //do something if (condition){ throw new IllegalAccessException("fake"); } public static void main(String args[]){ riskyMethod(); } После имени метода указывается тип (типы) возможных исключений, которые метод может сгенерировать: throws
Блок finally try { //какие-то действия doSomething(); //иногда бросает исключение doSomethingRisky(); }catch (NumberFormatException e) { handleState(); //обрабатываем исключение }finally { //действия, которые нужно выполнить независимо // от того, были ли сгенерировано исключение или нет doFinalStuff(); } Используя данный блок, добиваемся того, что некий набор действий выполнится независимо от того, сгенерировано исключение или нет
Пользовательские классы-исключения class TooHeavyBirdException extends Exception { private int weight; private String message; TooHeavyBirdException (int weight, String message) { this. weight = weight; this. message = message; } Создаем свой класс исключений на основе класса Exception
Пользовательские классы-исключения (продолжение) try {//какие-то действия if (condition){//бросаем наше исключение throw new TooHeavyBirdException (10, Веревка не выдержала птицу"); } //другие действия }catch (TooHeavyBirdException e) { showModalDialog(e.getMessage()); } Используется обычным способом. Зачастую создавать свои исключения не требуется.
Вредные советы Закрыть все опасные участки пустыми обработчиками (catch(...){ }) Использовать везде catch(Exception e){...} и throws Exception …
Правда ли что… После ситуации Error восстановиться невозможно? Обработчики должны следовать в восходящем порядке по иерархии классов-исключений? Некоторые бросаемые исключения можно не описывать в заголовке метода?
Ссылки П. Ноутон, Г. Шилдт, Java2 Б. Эккель, Философия Java
Q&A
Обработка исключительных ситуаций Андрей Дмитриев 2008