1 Обработка исключений в Java Одно из важнейших преимуществ Java – разработанный на уровне языка механизм обработки исключений. Исключение в Java - это объект, который описывает исключительное состояние, возникшее в каком-либо участке программного кода. Когда возникает исключительное состояние, создается объект класса Exception. Этот объект пересылается в метод, обрабатывающий данный тип исключительной ситуации. Наличие такого механизма позволяет «защитить» определенные участки кода от возникновения нештатных ситуаций различного рода, произвести их разумную обработку и перевести программу из возможного аварийного состояния (например, «зависания») в работоспособное, т.е. дать возможность продолжить ее выполнение, даже тогда, когда возникла ошибка времени выполнения. Исключения могут возбуждаться и «вручную» для того, чтобы сообщить о некоторых нештатных ситуациях.
2 Обработка исключений в Java Все классы исключений создают собственную иерархию, на вершине которой находится класс Throwable. Два непосредственных наследника класса Throwable делят иерархию подклассов исключений на две различные ветви: - класс Ехception используется для описания исключительных ситуации, которые должны перехватываться программным кодом пользователя; - класс Error, описывающий исключительные ситуации, которые при обычных условиях не могут быть перехвачены в пользовательской программе. Throwable Error Ехception RunTimeException … IOException ArithmeticExceptionArraysExceptoin … … … … Имена классов (типов) исключений определяются так, чтобы внести максимальное понимание какого типа та или иная исключительная ситуация ArraysIndexOutOfBounds …
3 Обработка исключений в Java К механизму обработки исключений в Java имеют отношение 5 ключевых слов: try, catch, throw, throws и finally. Схема работы этого механизма следующая: Мы пытаемся (try) выполнить блок кода и, если при этом возникает ошибка, система возбуждает (throw) исключение, которое в зависимости от его типа можно перехватить (catch) или передать обработчику по умолчанию (finally). Общая форма блока обработки исключений. try { // защищаемый блок кода } catch (ТипИсключения1 е) { // обработчик исключений типа ТипИсключения1 } catch (ТипИсключения2 е) { // обработчик исключений типа ТипИсключения2 throw e; // повторное возбуждение исключения } … finally { // Обработчик по умолчанию, если исключение не было обработано не одним из // блоков catch }
4 Обработка исключений в Java class Exc0 { public static void main(String args[ ]) { int d = (int) (Math.random()*2); int a = 42 / d; } Если возникнет ситуация, когда d=0, то вывод, полученный при запуске нашего примера. С:\> java Exc0 java.lang.ArithmeticException: / by zero at Exc0.main(Exc0.java:4) Такие исключительные ситуации (исключения) могут возникать в процессе выполнения программы и их автоматическая обработка приводит к прерыванию программы class Exc1 { public static void main(String args[ ]) { try { int d = (int) (Math.random()*2); int a = 42 / d; } catch(ArithmeticException e) { System.out.pruntln(Division by zero); } System.out.pruntln(Несмотря на это, мы продолжаем!); } Если возникнет ситуация, когда d=0, то вывод, полученный при запуске нашего примера. С:\> java Exc1 Division by zero Несмотря на это, мы продолжаем! Наличие такого механизма дает возможность «перехватить» исключение, провести его обработку и продолжить выполнение программы без прерывания.
5 Обработка исключений в Java В одном блоке программного кода могут возникать исключения различных типов. Для этого в Java можно использовать любое количество catch-разделов для try-блока. Наиболее специализированные классы исключений должны идти первыми, поскольку ни один подкласс не будет достигнут, если поставить его после суперкласса. class MultiCatch { public static void main(String args[]) { try { int a = args.length; System.out.println("a = " + a); int b = 10 / a; int d = (int) (Math.random()*10); int c[ ] = new int[d]; c[b] = 99; } catch (ArithmeticException e) { System.out.println("div by 0: " + e); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("array index oob: " + e + : + b); } catch(Throwable e) { System.out.println(Exception: " + e); } Ниже приведены результаты работы этой программы, запущенной и тем и другим способом. Программа перехватывает два различных типа исключений, причем за этими двумя специализированными обработчиками следует раздел catch общего назначения, перехватывающий все подклассы класса Throwable. Запуск без параметров, вызывает исключение «деление на нуль». Если командной строке задано два параметра (а=2), пример переживет оператор деления, но в следующих операторах, когда d случайно выберется меньше, чем 5 будет возбуждено исключение выхода индекса за границы массива ArrayIndexOutOfBounds. С:\> java MultiCatch а = 0 div by 0: java.lang.ArithmeticException: / by zero C:\> java MultiCatch 1 34 a = 2 array index oob: java.lang.ArrayIndexOutOfBoundsException: 5
6 Обработка исключений в Java Вложенные операторы try Операторы try можно вкладывать друг в друга аналогично тому, как можно создавать вложенные области видимости переменных. Если у оператора try низкого уровня нет раздела catch, соответствующего возбужденному исключению, стек будет развернут на одну ступень выше, и в поисках подходящего обработчика будут проверены разделы catch внешнего оператора try. Если ни у одного из вложенных блоков try не найдется подходящего обработчика catch, программа обработает исключение в автоматическом режиме и выдаст содержимое стэка выполнения… finally Иногда требуется гарантировать, что определенный участок кода будет выполняться независимо от того, какие исключения были возбуждены и перехвачены. Для создания такого участка кода используется ключевое слово finally. Даже в тех случаях, когда в методе нет соответствующего возбужденному исключению раздела catch, блок finally будет выполнен до того, как управление перейдет к операторам, следующим за разделом try. У каждого раздела try должен быть по крайней мере или один раздел catch или блок finally. Блок finally очень удобен для закрытия файлов и освобождения любых других ресурсов, захваченных для временного использования в начале выполнения метода.
7 Обработка исключений в Java class FinallyMultiCatch { public static void main(String args[]) { try { int a = args.length; System.out.println("a = " + a); int b = 10 / a; int d = (int) (Math.random()*10); int c[ ] = new int[d]; c[b] = 99; } catch (ArithmeticException e) { System.out.println("div by 0: " + e); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("array max index " + d + \n + e + : + b); } finally { System.out.println( Не нужно думать, что все хорошо…"); } С:\> java MultiCatch а = 0 div by 0: java.lang.ArithmeticException: / by zero Не нужно думать, что все хорошо… C:\> java MultiCatch 1 34 a = 2 array max index 4 java.lang.ArrayIndexOutOfBoundsException: 5 Не нужно думать, что все хорошо… C:\> java MultiCatch 1 34 a = 2 Не нужно думать, что все хорошо… Раздел finally выполняется в любом случае, даже когда исключения не возбуждаются…
8 Обработка исключений в Java throw Оператор throw используется для возбуждения исключения «вручную». Для того, чтобы сделать это, нужно иметь объект подкласса класса Throwable, который можно либо получить как параметр оператора catch, либо создать с помощью оператора new. throw ОбъектТипаThrowable; При достижении этого оператора нормальное выполнение кода немедленно прекращается. Ближайший окружающий блок try проверяется на наличие соответствующего возбужденному исключению обработчика catch. Если такой отыщется, управление передается ему. Если нет, проверяется следующий из вложенных операторов try, и так до тех пор пока либо не будет найден подходящий раздел catch, либо обработчик исключений исполняющей системы Java не остановит программу, выведя при этом состояние стека вызовов. throws Если метод способен возбуждать исключения, которые он сам не обрабатывает, он должен объявить о таком поведении, чтобы вызывающие методы могли защитить себя от этих исключений. Для задания списка исключений, которые могут возбуждаться методом, используется ключевое слово throws. Если метод в явном виде (т.е. с помощью оператора throw) возбуждает исключение соответствующего класса, тип класса исключений должен быть указан в операторе throws в объявлении этого метода. С учетом этого наш прежний синтаксис определения метода должен быть расширен следующим образом: тип имя_метода(список аргументов) throws список_исключений { }
9 Обработка исключений в Java Создание собственных исключений (подклассов Exception) Механизм генерации и обработки исключений можно подстроить для решения собственных задач. class MyException extends Exception { private int detail; MyException(int a) { detail = a; } public String toString() { return "MyException[" + detail + "]"; } class ExceptionDemo { static void compute(int a) throws MyException { System.out.println("called computer + a + ")."); if (a > 10) throw new MyException(a); System.out.println("normal exit."); } public static void main(String args[]) { try { compute(1); compute(20); } catch (MyException e) { System.out.println("caught" + e); } Создается класс MyException – наследник класса Exception. У этого подкласса есть специальный конструктор, который записывает в переменную объекта целочисленное значение, и совмещенный метод toString, выводящий значение, хранящееся в объекте-исключении. Класс ExceptionDemo определяет метод compute, который возбуждает (throw), но сам не обрабатывает (throws) исключение типа MyExcepton. Исключение возбуждается, когда значение параметра метода больше 10. Метод main в защищенном блоке вызывает метод compute сначала с допустимым значением, а затем - с недопустимым (больше 10), что позволяет продемонстрировать работу при обоих путях выполнения кода. С:\> java ExceptionDemo called compute(1). normal exit. called compute(20). caught MyException[20]