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

Зачем использовать вложенный блок try

Иногда может возникнуть ситуация, когда часть блока может вызвать одну ошибку, а сам блок целиком может вызвать другую ошибку. В таких случаях обработчики исключений должны быть вложенными.

Синтаксис

try {
   statement 1;
   statement 2;
   try {
      statement 1;
      statement 2;
   }
   catch(Exception e) {
      // catch the corresponding exception  
   }  
}
catch(Exception e) {
   // catch the corresponding exception
}
   .............

Пример

// An example of nested try statements.
class NestTry {
public static void main(String args[]) {
    try {
        int a = args.length;
        /* If no command-line args are present,
        the following statement will generate
        a divide-by-zero exception. */
        int b = 42 / a;
        System.out.println("a = " + a);
        try { // nested try block
            /* If one command-line arg is used,
            then a divide-by-zero exception
            will be generated by the following code. */
            if(a==1) a = a/(a-a); // division by zero
            /* If two command-line args are used,
            then generate an out-of-bounds exception. */
            if(a==2) {
                int c[] = { 1 };
                c[42] = 99; // generate an out-of-bounds exception
            }
        } catch(ArrayIndexOutOfBoundsException e) {
        System.out.println("Array index out-of-bounds: " + e);
        }
    } catch(ArithmeticException e) {
    System.out.println("Divide by 0: " + e);
    }
  }
}

Как видите, эта программа вкладывает один блок try в другой. Программа работает следующим образом.

Без командной строки. Когда вы запускаете программу без аргументов командной строки, внешний блок try генерирует исключение деления на ноль.

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

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

C:\>java NestTry
Divide by 0: java.lang.ArithmeticException: / by zero
C:\>java NestTry One
a = 1
Divide by 0: java.lang.ArithmeticException: / by zero
C:\>java NestTry One Two
a = 2
Array index out-of-bounds:
java.lang.ArrayIndexOutOfBoundsException:42

Является ли вложенный блок try-catch антишаблоном?

Иногда это неизбежно, особенно если ваш код восстановления может вызвать исключение. Некрасиво, но иногда альтернатив нет.

Дополнительные примечания

  • Если внутренний оператор try не имеет соответствующего оператора catch для определенного исключения, управление передается следующему оператору try обработчикам catch, который ожидаются для соответствующего оператора catch.
  • Это продолжается до тех пор, пока один из операторов catch не завершится успешно или пока не будут выполнены все вложенные операторы try.
  • Если ни один из операторов catch не совпадает, тогда система выполнения Java обработает исключение. Каждый раз, когда блок try не имеет обработчика catch для определенного исключения, тогда блоки catch родительского блока try проверяются на наличие этого исключения, если обнаруживается совпадение с выполнением этого блока catch. ни блок catch, ни родительский блок catch не обрабатывают исключение, тогда для исключения будет показано сообщение, сгенерированное системой времени выполнения, аналогично тому, что мы видим, когда не обрабатываем исключение.
  • Когда используются вложенные блоки try, сначала выполняется внутренний блок try. Любое исключение, созданное во внутреннем блоке try, перехватывается в соответствующем блоке catch. Если соответствующий блок catch не найден, блок catch внешнего блока try проверяется до тех пор, пока все вложенные операторы try исчерпаны. Если соответствующие блоки не найдены, среда выполнения Java обрабатывает выполнение.

Программа

// An example of nested try statements.
class NestTry {
public static void main(String args[]) {
try {
  int a = args.length;
  /* If no command-line args are present,
  the following statement will generate
  a divide-by-zero exception. */
  int b = 42 / a;
  System.out.println("a = " + a);
  try { // nested try block
    /* If one command-line arg is used,
    then a divide-by-zero exception
    will be generated by the following code. */
    if(a==1) a = a/(a-a); // division by zero
    /* If two command-line args are used,
    then generate an out-of-bounds exception. */
    if(a==2) {
      int c[] = { 1 };
      c[42] = 99; // generate an out-of-bounds exception
  }
  } catch(ArrayIndexOutOfBoundsException e) {
  System.out.println("Array index out-of-bounds: " + e);
}
} catch(ArithmeticException e) {
System.out.println("Divide by 0: " + e);
}
}
}

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

C:\>java NestTry
Divide by 0: java.lang.ArithmeticException: / by zero
C:\>java NestTry One
a = 1
Divide by 0: java.lang.ArithmeticException: / by zero
C:\>java NestTry One Two
a = 2
Array index out-of-bounds:
java.lang.ArrayIndexOutOfBoundsException:42

Вложенность операторов try может происходить менее очевидным образом, когда задействованы вызовы методов. Например, вы можете заключить вызов метода в блок try. Внутри этого метода находится еще один оператор try. В этом случае попытка внутри метода по-прежнему вложена во внешний блок попытки, который вызывает метод. Вот предыдущая программа, перекодированная таким образом, что вложенный блок try перемещается внутрь метода nesttry():

/* Try statements can be implicitly nested via
calls to methods. */
class MethNestTry {
static void nesttry(int a) {
  try { // nested try block
    /* If one command-line arg is used,
    then a divide-by-zero exception
    will be generated by the following code. */
    if(a==1) a = a/(a-a); // division by zero
    /* If two command-line args are used,
    then generate an out-of-bounds exception. */
    if(a==2) {
      int c[] = { 1 };
      c[42] = 99; // generate an out-of-bounds exception
  }
  } catch(ArrayIndexOutOfBoundsException e) {
      System.out.println("Array index out-of-bounds: " + e);
  }
}
public static void main(String args[]) {
  try {
    int a = args.length;
    /* If no command-line args are present,
    the following statement will generate
    a divide-by-zero exception. */
    int b = 42 / a;
    System.out.println("a = " + a);
    nesttry(a);
  } catch(ArithmeticException e) {
    System.out.println("Divide by 0: " + e);
  }
}
}

Вывод этой программы идентичен предыдущему примеру.

Спасибо за чтение. Приятного обучения 😄

Присоединяйтесь к группе Mouad Oumous Java WhatsApp JOIN

Присоединяйтесь к Telegram-каналу Mouad Oumous JOIN

Поддержите нашу публикацию, подписавшись на нее