Смекни!
smekni.com

Общие представления о языке Java 5 (стр. 49 из 68)

Про наступившую исключительную ситуацию говорят, что она возникает, либо – что она возбуждается. В английском языке для этого используется слово throw – “бросить”. Поэтому иногда в переводной литературе используют дословный перевод “бросается исключительная ситуация”.

Общий случай использования защищённого блока программного кода и перехвата исключительных ситуаций выглядит так:

try{

операторы0;

}

catch (ТипИсключения1 переменная1){

операторы1;

}

catch (ТипИсключения2 переменная2){

операторы2;

}

catch (ТипИсключенияN переменнаяN){

операторыN;

}

finally{

операторы;

}

Отметим, что при задании блоков try-catch-finally после фигурных скобок точкой с запятой “;” можно не ставить, как и всегда в случае использования фигурных скобок. Но можно и ставить - по усмотрению программиста.

Если исключительных ситуаций не было, операторы0 в блоке try выполняются в обычном порядке, после чего выполняются операторы в блоке finally. Если же возникла исключительная ситуация в блоке try, выполнение блока прерывается, и идёт перехват исключений в блоках catch (“перехватить”). В качестве параметра оператора catch задаётся ссылочная переменная, имеющая тип той исключительной ситуации, которую должен перехватить данный блок. Чаще всего эту переменную называют e (по первой букве от exception). Если тип исключения совместим с типом, указанном в качестве параметра, выполняется соответствующий оператор. После чего проверок в следующих блоках catch не делается.

После проверок и, возможно, перехвата исключения в блоках catch выполняются операторы блока finally. Его обычно используют для высвобождения ресурсов, и поэтому часто называют блоком "очистки ресурсов". Специальных операторов или зарезервированных конструкций для обработки в блоке finally нет. Отличие кода внутри блока finally от кода, стоящего после оператора try…finally, возникает только при наличии внутри блоков try или catch операторов break, continue, return или System.exit, то есть операторов, прерывающих работу блока программного кода. В этом случае независимо от их срабатывания или несрабатывания сначала происходит выполнение операторов блока finally, и только потом происходит переход в другое место программы в соответствии с оператором прерывания.

Пример обработки исключений:

void myETest(String s,double y){

double x, z;

try{

x=Double.parseDouble(s);

z=Math.sqrt(x/y);

} catch(ArithmeticException e){

System.out.println("Деление на ноль");

} catch(NumberFormatException e){

System.out.println("Корень из отрицательного числа!");

}

};

Иерархия исключительных ситуаций

Исключительные ситуации в Java являются объектами. Их типы являются классами-потомками объектного типа Throwable (от throw able – “способный возбудить исключительную ситуацию”). От Throwable наследуются классы Error (“Ошибка”) и Exception (“Исключение”). Экземплярами класса Error являются непроверяемые исключительные ситуации, которые невозможно перехватить в блоках catch. Такие исключительные ситуации представляют катастрофические ошибки, после которых невозможна нормальная работа приложения. Экземплярами класса Exception и его потомков являются проверяемые исключительные ситуации. Кроме одного потомка – класса RuntimeException (и его потомков). Имя этого класса переводится как “Исключительные ситуации времени выполнения”.

Классы исключительных ситуаций либо предопределены в стандартных пакетах (существуют исключительные ситуации ArithmeticException для арифметических операций в пакете java.lang, IOException в пакете java.io, и так далее), либо описываются пользователем как потомки класса Exception или его потомков.

В Java типы-исключения принято именовать, оканчивая имя класса на “Exception” (“Исключение”) для проверяемых исключений или на “Error” (“Ошибка”) для непроверяемых.

По правилу совместимости типов исключительная ситуация типа-потомка всегда может быть обработана как исключение прародительского типа. Поэтому порядок следования блоков catch имеет большое значение: обработчик исключения более общего типа следует писать всегда после обработчика для его типа-потомка, иначе обработчик потомка никогда не будет вызван.

В приведённом выше примере вместо NumberFormatException можно поставить Exception, так как других типов исключений кроме NumberFormatException сюда доходить не может. В этом случае метод выглядит так:

void myETest(String s,double y){

double x, z;

try{

x=Double.parseDouble(s);

z=Math.sqrt(x/y);

} catch(ArithmeticException e){

System.out.println("Деление на ноль");

} catch(Exception e){

System.out.println("Корень из отрицательного числа!");

}

};

Но если бы мы попробовали таким же образом заменить тип исключения в первом блоке catch, то блок для исключений типа Exception всегда перехватывал бы управление, и обработчик для NumberFormatException никогда бы не срабатывал. Пример такого неправильно написанного кода:

void myETest(String s,double y){

double x, z;

try{

x=Double.parseDouble(s);

z=Math.sqrt(x/y);

} catch(Exception e){

System.out.println("Деление на ноль");

} catch(NumberFormatException e){

System.out.println("Корень из отрицательного числа!");

}

};

В таких случаях среда разработки NetBeans выдаст сообщение вида “exception java.lang.NumberFormatException has already been caught” – “исключение java.lang.NumberFormatException уже было перехвачено”.

Объявление типа исключительной ситуации и оператор throw

Для того чтобы задать собственный тип исключительной ситуации, требуется задать соответствующий класс. Он должен быть наследником от какого-либо класса исключительной ситуации.

Например, зададим класс исключения, возникающего при неправильном вводе пользователем пароля:

class WrongPasswordException extends Exception {

WrongPasswordException(){ // конструктор

System.out.println(”Wrong password!”);

}

}

Создание объекта-исключения может проводиться в произвольном месте программы обычным образом, как для всех объектов, при этом возбуждения исключения не происходит.

Программное возбуждение исключительной ситуации производится с помощью оператора throw, после которого указывается оператор создания объекта-исключения:

throw new ТипИсключения();

Например,

throw new WrongPasswordException();

Если после частичной обработки требуется повторно возбудить исключительную ситуацию e, используется вызов

throw e;

Для проверяемых исключений всегда требуется явное возбуждение. При возбуждении исключения во время выполнения какого-либо метода прерывается основной ход программы, и идёт процесс обработки исключения. Его иногда называют “всплыванием” исключения по аналогии со всплыванием пузырька. Если в методе исключение данного типа не перехватывается, исполняется соответствующий блок finally, если он есть, и всплывание продолжается – происходит выход из текущего метода в метод более высокого уровня. Соответственно, исключение начинает обрабатываться на уровне этого метода. Если оно не перехватывается, происходит выход на ещё более высокий уровень, и так далее.

Если в методе исключение данного типа перехватывается, всплывание прекращается. Если же ни на каком уровне исключение не перехвачено – оно обрабатывается исполняющей средой. При этом выполняются действия, предусмотренные в конструкторе исключения, а затем система выводит служебную информацию о том, где и какого типа исключение возникло.

Исключительная ситуация – это особая, экстремальная ситуация, не планируемая заранее. Не следует использовать исключения в качестве конструкций, на которых основаны часто повторяющиеся в программе действия.

Задание: усовершенствовать класс WrongPasswordException таким образом, чтобы сообщение об ошибке появлялось в виде диалогового окна.

Объявление метода, который может возбуждать исключительную ситуацию. Зарезервированное слово throws

Формат объявления функции, которая может возбуждать проверяемые исключительные ситуации, следующий:

Модификаторы Тип Имя(список параметров)

throws ТипИсключения1, ТипИсключения2,…, ТипИсключенияN

{

Тело функции

}

Аналогичным образом объявляется конструктор, который может возбуждать проверяемые исключительные ситуации:

Модификаторы ИмяКласса(список параметров)

throws ТипИсключения1, ТипИсключения2,…, ТипИсключенияN

{

Тело конструктора

}

Слово throws означает “возбуждает исключительную ситуацию” (дословно – “бросает”).

Непроверяемые исключения генерируются и обрабатываются системой автоматически – как правило, приводя к завершению приложения. При этом их типы нигде не указываются, и слово throws в заголовке метода указывать не надо.

Если в теле реализуемого метода используется вызов метода, который может возбуждать исключительную ситуацию, и это исключение не перехватывается, в заголовке реализуемого метода требуется указывать соответствующий тип возбуждаемого исключения. Если же это исключение порождается внутри защищённого блока программного кода, и в каком-либо блоке catch перехватывается этот тип исключения или более общий (прародительский), то указывать в заголовке тип исключения не следует.

Как мы уже знаем, в теле метода может быть использован оператор throw, возбуждающий исключительную ситуацию. В этом случае если объект-исключение не перехвачен, в заголовке метода требуется указывать соответствующий тип возбуждаемого исключения. В частности, оператор throw может быть использован для порождения исключения другого типа после обработки перехваченного исключения в блоке catch.

Если в родительском классе задан метод, в заголовке которого указан тип какой-либо исключительной ситуации, а в классе-потомке этот метод переопределяется, в переопределяемом методе также требуется указывать совместимый тип исключительной ситуации. При этом может быть указан либо тот же тип, либо тип исключительной ситуации – потомка от данного типа. В противном случае на этапе компиляции выдаётся диагностика ошибки.