Оператор try-catch-finally

  1. Применение операторов catch
  2. Объявление нескольких исключений в одном блоке catch (multi-catch блок)
  3. Оператор finally

1. Применение операторов catch

Общая форма блока обработки исключений:

public class ExceptionDemo1 {
    public static void main(String[] args) {
        try {
            // блок кода, в котором отслеживаются ошибки
        } catch (ExceptionType1 e) {
            // обработчик исключений типа ExceptionType1
        } catch (ExceptionType2 e) {
            // обработчик исключений типа ExceptionType2
        } finally {
            // блок кода, который должен быть выполнен после завершения блока try
        }
    }
}

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

Когда возбуждается исключение, каждый оператор catch проверяется по порядку, и первый из них, чей тип соответствует исключению, выполняется.

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

Рассмотрим пример применения нескольких операторов catch:

public class MultiCatch {
    public static void main(String[] args) {
        try {
            int a = args.length;
            int b = 42 / a;
            int[] c = new int[a];
            c[a] = 6;
        } catch (ArithmeticException e) {
            System.out.println("Деление на ноль." + e);
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        System.out.println("Уже после блока try-catch-catch.");
    }
}

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

public class SuperSubCatch {
    public static void main(String[] args) {
        try {
            int a = 0;
            int b = 42 / a;
        } catch (Exception e) {
            System.out.println("Перехват исключений общего класса Exception.");
        } /*catch (ArithmeticException e) {
            //ОШИБКА: недостижимый код !
            System.out.println("Этoт код вообще недостижим.");
        }*/
    }
}

2. Объявление нескольких исключений в одном блоке catch (multi-catch блок)

Было:

try {
  ...
} catch(IllegalStateException e){
  System.out.println(e.getMessage());
} catch(SQLException e){
  System.out.println(e.getMessage());
} catch(ContextException e){
  System.out.println(e.getMessage());
}
Стало после Java 7:
try {
  ...
} catch(IllegalStateException | SQLException | ContextException e){
   System.out.println(e.getMessage());
}

Пример использования multi-catch блока:

public class MultiCatch2 {
    public static void main(String[] args) {
        try {
            int a = args.length;
            int b = 42 / a;
            int[] c = new int[a];
            c[a] = 6;
        } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
            System.out.println("Ошибка." + e);
        }
        System.out.println("Уже после блока try-catch.");
    }
}

Параметр оператора catch должен быть фактически завершенным (effective final). Это означает, что ему нельзя присваивать новое значение в блоке оператора catch или же он должен быть явно объявлен как final.

Multi-catch block может содержать только исключения не входящие в одну иерархию.

3. Оператор finally

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

Оператор finallу образует блок кода, который будет выполнен по завершении блока операторов try-catch, но перед следующим за ним кодом.

Блок оператора finallу выполняется независимо от того, выброшено ли исключение или нет. Если исключение выброшено, блок оператора finallу выполняется, даже при условии, что ни один из операторов catch не совпадает с этим исключением. В любой момент, когда метод собирается возвратить управление вызывающему коду из блока оператора try-саtch (через необработанное исключение или явным образом через оператор return), блок оператора finallу выполняется перед возвратом управления из метода.

public class FinallyUse {
    // Выход из метода через исключение
    public static void procA() {
        try {
            System.out.println("Внутри procA");
            throw new RuntimeException("demo");
        } finally {
            System.out.println("finally для procA ");
        }
    }

    // Возврат изнутри try-блока
    public static void procB() {
        try {
            System.out.println("Внутри procB");
            return;
        } finally {
            System.out.println("finally для procB ");
        }
    }

    // Нормальное выполнение try-блока
    public static void procC() {
        try {
            System.out.println("Внутри procC");
        } finally {
            System.out.println("finally procC");
        }
    }

    public static void main(String[] args) {
        try {
            procA();
        } catch (Exception e) {
            System.out.println("Исключение выброшено");
        }
        procB();
        procC();
    }
}
Read also:
Comments