finally

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

finally создает блок кода, который будет выполнен после завершения блока try/catch, но перед кодом, следующим за try/catch. Блок finally выполняется независимо от того, возбуждено исключение или нет. Если исключение возбуждено, блок finally выполняется, даже если ни один оператор catch этому исключению не соответствует. В любой момент, когда метод собирается возвратить управление вызывающему коду изнутри блока try/catch — из-за необработанного исключения, или явным применением оператора return — блок finally будет выполнен перед возвратом управления из метода. Это может быть удобно для закрытия файловых дескрипторов либо освобождения других ресурсов, которые были получены в начале метода и должны быть освобождены перед возвратом. Оператор finally необязателен. Однако каждый оператор try требует наличия, по крайней мере, одного оператора catch или finally. Ниже приведен пример программы, которая показывает три метода, возвращающих управление разными способами, но ни один из них не пропускает выполнения блока finally.

class FinallyDemo {
// Возбуждает исключение из метода.
static void procAO {
try {
System.out.println("внутри procA") ;
throw new RuntimeException("демо");
}
finally {
System.out.println("блок finally procA");
}
}
// Возврат управления в блоке try.
static void procB() {
try {
System.out.println("внутри procB");
return;
} finally {
System.out.println("блок finally procB");
}
}
// Нормальное выполнение блока try.
static void procCO {
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 ();
}
}

В этом примере procA () преждевременно прерывает выполнение в блоке try, возбуждая исключение. Блок finally все равно выполняется. В procB () возврат управления осуществляется в блоке try оператором return. Блок finally выполняется перед возвратом из procB (). В procC () блок try выполняется нормально, без ошибок. Однако блок finally выполняется все равно.

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

внутри procА
блок finally procА
Исключение перехвачено
внутри procB
блок finally procB
внутри procC
блок finally procC