Try, catch и finally
Try и catch: попытка и обработка
Когда участок кода может завершиться исключением, его можно поместить в блок
try. Сразу после него указывают один или несколько
блоков catch — они описывают, что делать,
если возникло исключение подходящего типа.
try {
int result = 10 / 0;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("caught");
}
System.out.println("done");
При выполнении деления возникает ArithmeticException.
Оставшаяся часть блока try уже не выполняется:
управление переходит в подходящий catch.
После его завершения программа продолжает работу со строки после всей конструкции.
Поэтому пример выведет сначала caught, а затем done.
Переменная e содержит объект возникшего исключения.
С ним можно работать как с обычным объектом соответствующего типа.
Catch срабатывает только для подходящего типа
Тип в круглых скобках определяет, какие исключения может обработать конкретный
catch. Здесь работает уже знакомое наследование:
обработчик подходит не только для указанного класса, но и для его подклассов.
try {
String[] values = {"10", "20"};
int index = Integer.parseInt("5");
System.out.println(values[index]);
} catch (NumberFormatException e) {
System.out.println("bad number");
} catch (IndexOutOfBoundsException e) {
System.out.println("bad index");
}
Строка "5" успешно превращается в число, поэтому первый
catch не нужен. Затем программа обращается
к несуществующему элементу массива, возникает IndexOutOfBoundsException,
и управление переходит во второй обработчик.
Если обработчиков несколько, Java проверяет их сверху вниз и использует первый подходящий. Поэтому более общий тип нельзя ставить перед его более конкретным подклассом: иначе нижний обработчик никогда не смог бы сработать.
try {
int value = Integer.parseInt("abc");
} catch (Exception e) {
System.out.println("exception");
} catch (NumberFormatException e) {
System.out.println("number");
}
NumberFormatException является подклассом
Exception, поэтому первый
catch уже перехватывает все такие исключения.
Более конкретные обработчики размещают раньше более общих.
Если исключения нет, catch пропускается
Блок catch не является обязательной частью обычного пути выполнения.
Если весь try завершился без исключения,
обработчики просто пропускаются, и программа идёт дальше.
try {
int result = 10 / 2;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("caught");
}
System.out.println("done");
Здесь исключения нет, поэтому программа выведет 5, а затем done.
Finally выполняется после try и catch
После try и возможных
catch можно добавить блок
finally. Он предназначен для кода,
который должен выполниться после этой попытки независимо от того,
возникло исключение или нет.
try {
System.out.println("try");
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("catch");
} finally {
System.out.println("finally");
}
System.out.println("done");
Этот код выведет try, затем catch,
после этого finally и только потом done.
Если исключение в блоке try не возникнет,
catch будет пропущен, но
finally всё равно выполнится.
Так конструкция разделяет три роли: try содержит код,
в котором может возникнуть исключительная ситуация,
catch реагирует на подходящее исключение,
а finally выполняет действие после завершения этой попытки.