Программирование на языке Java

Вложенные операторы try


Операторы try можно вкладывать друг в друга аналогично тому, как можно создавать вложенные области видимости переменных. Если у оператора try низкого уровня нет раздела catch, соответствующего возбужденному исключению, стек будет развернут на одну ступень выше, и в поисках подходящего обработчика будут прове­рены разделы catch внешнего оператора try. Вот пример, в котором два оператора try вложены друг в друга посредством вызова метода.

class MultiNest {

static void procedure() {

try {

     int c[] = { 1 };

     c[42] = 99;

}



catch(ArrayIndexOutOfBoundsException e) {

System.out.println("array index oob: " + e);

} }

public static void main(String args[]) {

try {

     int a = args.length();

     System.out.println("a = " + a);

     int b = 42 / a;

     procedure();

}

catch (ArithmeticException e) {

System.out.println("div by 0: " + e);

}

} }

 

throw

Оператор throw используется для возбуждения исключения «вруч­ную». Для того, чтобы сделать это, нужно иметь объект подкласса клас­са Throwable, который можно либо получить как параметр оператора catch, либо создать с помощью оператора new. Ниже приведена общая форма оператора throw.

throw ОбъектТипаThrowable;

При достижении этого оператора нормальное выполнение кода немед­ленно прекращается, так что следующий за ним оператор не выполня­ется. Ближайший окружающий блок try проверяется на наличие соот­ветствующего возбужденному исключению обработчика catch. Если такой отыщется, управление передается ему. Если нет, проверяется следующий из вложенных операторов try, и так до тех пор пока либо не будет най­ден подходящий раздел catch, либо обработчик исключений исполняю­щей системы Java не остановит программу, выведя при этом состояние стека вызовов. Ниже приведен пример, в котором сначала создается объект-исключение, затем оператор throw возбуждает исключительную ситуацию, после чего то же исключение возбуждается повторно — на этот раз уже кодом перехватившего его в первый раз раздела catch.


class ThrowDemo {



static void demoproc() {



try {



throw new NullPointerException("demo");



}



catch (NullPointerException e) {



System.out.println("caught inside demoproc");



throw e;



} }



public static void main(String args[]) {



try {



demoproc();



}



catch(NulPointerException e) {



System.out.println("recaught: " + e);



}



} }



В этом примере обработка исключения проводится в два приема. Метод main создает контекст для исключения и вызывает demoproc. Метод demoproc также устанавливает контекст для обработки исключе­ния, создает новый объект класса NullPointerException и с помощью опе­ратора throw возбуждает это исключение. Исключение перехватывается в следующей строке внутри метода demoproc, причем объект-исключение доступен коду обработчика через параметр e. Код обработчика выводит сообщение о том, что возбуждено исключение, а затем снова возбуждает его с помощью оператора throw, в результате чего оно передается обра­ботчику исключений в методе main. Ниже приведен результат, получен­ный при запуске этого примера.

С:\> java ThrowDemo

caught inside demoproc



recaught: java.lang.NullPointerException: demo



 



throws

Если метод способен возбуждать исключения, которые он сам не об­рабатывает, он должен объявить о таком поведении, чтобы вызывающие методы могли защитить себя от этих исключений. Для задания списка исключений, которые могут возбуждаться методом, используется ключе­вое слово throws. Если метод в явном виде (т.е. с помощью оператора throw) возбуждает исключе­ние соответствующего класса, тип класса исключений должен быть ука­зан в операторе throws в объявлении этого метода. С учетом этого наш прежний синтаксис определения метода должен быть расширен следую­щим образом:

тип имя_метода(список аргументов) throws список_исключений {}



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



class ThrowsDemo1 {



static void procedure() {



System.out.println("inside procedure");



throw new IllegalAccessException("demo");



}



public static void main(String args[]) {



procedure();



} }



Для того, чтобы мы смогли оттранслировать этот пример, нам при­дется сообщить транслятору, что procedure может возбуждать исключе­ния типа IllegalAccessException и в методе main добавить код для обработки этого типа исключений :

class ThrowsDemo {



static void procedure() throws IllegalAccessException {



System.out.println(" inside procedure");



throw new IllegalAccessException("demo");



}



public static void main(String args[]) {



try {



procedure();



}



catch (IllegalAccessException e) {



System.out.println("caught " + e);



}



} }



Ниже приведен результат выполнения этой программы.

С:\> java ThrowsDemo

inside procedure



caught java.lang.IllegalAccessException: demo



 



finally



Иногда требуется гарантировать, что определенный участок кода будет выпол­няться независимо от того, какие исключения были возбуждены и пере­хвачены. Для создания такого участка кода используется ключевое слово finally. Даже в тех случаях, когда в методе нет соответствующего воз­бужденному исключению раздела catch, блок finally будет выполнен до того, как управление перейдет к операторам, следующим за разделом try. У каждого раздела try должен быть по крайней мере или один раз­дел catch или блок finally. Блок finally очень удобен для закрытия файлов и освобождения любых других ресурсов, захваченных для времен­ного использования в начале выполнения метода. Ниже приведен пример класса с двумя     методами, завершение которых происходит по разным причинам, но в обоих перед выходом выполняется код раздела finally.

class FinallyDemo {



static void procA() {



try {



System.out.println("inside procA");



throw new RuntimeException("demo");





}



finally {



System.out.println("procA's finally");



} }



static void procB() {



try {



System.out.println("inside procB");



return;



}



finally {



System.out.println("procB's finally");



} }



public static void main(String args[]) {



try {



procA();



}



catch (Exception e) {}



procB();



} }



В этом примере в методе procA из-за возбуждения исключения про­ исходит преждевременный выход из блока try, но по пути «наружу» вы­полняется раздел finally. Другой метод procB завершает работу выпол­нением стоящего в try-блоке оператора return, но и при этом перед выходом из метода выполняется программный код блока finally. Ниже приведен результат, полученный при выполнении этой программы.

С:\> java FinallyDemo

inside procA



procA's finally



inside procB



procB's finally



 




Содержание раздела