27

Всегда ли выполняется блок finally в Java?

34

Тема: Выполнение блока finally в Java

У меня возник вопрос по поводу выполнения блока finally в следующем коде:

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("Не знаю, будет ли это выведено на экран");
}

Могу ли я быть абсолютно уверенным, что блок finally всегда будет выполнен независимо от результата выполнения метода something()? Даже если в процессе выполнения something() произойдет необработанное исключение или произойдет вызов System.exit()? Спасибо за помощь!

4 ответ(ов)

30

Да, блок finally будет вызван после выполнения блоков try или catch.

Единственные случаи, когда finally не будет вызван:

  1. Если вы вызываете System.exit()
  2. Если вы вызываете Runtime.getRuntime().halt(exitStatus)
  3. Если виртуальная машина Java (JVM) аварийно завершает работу
  4. Если JVM застревает в бесконечном цикле (или в каком-либо другом не прерываемом, не завершающем выражении) в блоке try или catch
  5. Если операционная система принудительно завершает процесс JVM; например, команда kill -9 <pid> в UNIX
  6. Если хост-система выходит из строя; например, отключение питания, ошибка оборудования, паника ОС и т. д.
  7. Если блок finally должен быть выполнен потоками-демонами, и все остальные недемоны завершили свою работу до вызова finally
6

В приведенном вами коде, метод test() возвращает 0, но перед этим выполняется блок finally, который печатает сообщение "something is printed".

Вот краткое пояснение:

  1. Основной метод (main): вызывает метод test() и выводит его результат на экран.
  2. Метод test():
    • Внутри метода есть блок try, который возвращает значение 0.
    • Однако, перед тем как фактически завершить выполнение метода и вернуть значение, Java всегда выполняет блок finally (если он присутствует).
    • В данном случае, в блоке finally выполняется вывод сообщения в консоль, после чего возвращается значение 0.

Таким образом, в выводе сначала будет напечатано сообщение из блока finally, а затем возвращаемое значение.

Поскольку блок finally выполняется всегда, вы получите следующий вывод:

something is printed
0

Обратите внимание, что если в блоке try или finally возникает исключение, то оно может изменить поведение. Тем не менее, в вашем коде исключений нет, и всё работает именно так, как описано.

4

В дополнение к этому, хотя это и считается плохой практикой, если внутри блока finally есть оператор return, он переопределит любой return, выполненный в блоке try. То есть следующий код вернёт false:

try { return true; } finally { return false; }

То же самое касается выбрасывания исключений из блока finally.

1

Я попробовал приведенный выше пример с небольшими изменениями:

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

Этот код выводит:

finally trumps return.
2

Это происходит потому, что когда выполняется return i;, переменная i имеет значение 2. После этого выполняется блок finally, где переменной i присваивается значение 12, и затем выполняется System.out.println.

После завершения выполнения блока finally блок try возвращает 2, а не 12, потому что этот оператор return больше не выполняется повторно.

Если вы отладите этот код в Eclipse, вам может показаться, что после выполнения System.out из блока finally снова выполняется оператор return из блока try. Но это не так. На самом деле возвращается значение 2.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь