Учитывая этот код, могу ли я быть абсолютно уверен, что блок finally
всегда выполняется, вне зависимости от того, что something()
?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("i don't know if this will get printed out.");
}
Да, finally
, вызывается после выполнения блоков try или catch.
Единственными моментами, которые, finally
, не будут называться, являются:
System.exit()
;try
или catch
;thread.stop()
не обязательно препятствует выполнению блока finally
.
finally
будет вызываться после блока try
и перед передачей управления следующим операторам. Это согласуется с блоком try, включающим бесконечный цикл и, следовательно, блок finally, который фактически никогда не вызывается.
Пример кода:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("finally trumps return.");
}
}
Вывод:
finally trumps return.
0
finally
с return 2;
не допускается (ошибка компилятора).
Кроме того, хотя это плохая практика, если в блоке finally есть оператор return, он будет превзойти любой другой возврат из обычного блока. То есть, следующий блок вернет false:
try { return true; } finally { return false; }
То же самое, что бросает исключения из блока finally.
Вот официальные слова из спецификации языка Java.
14.20.2. Выполнение try-finally и try-catch-finally
Оператор
try
с блокомfinally
выполняется, сначала выполнив блокtry
. Тогда есть выбор:
- Если выполнение блока
try
завершается нормально, [...]- Если выполнение блока
try
завершается внезапно из-заthrow
значения V, [...]- Если выполнение блока
try
завершается внезапно по любой другой причине R, выполняется блокfinally
. Тогда есть выбор:
- Если блок finally завершается нормально, то оператор
try
завершается внезапно по причине R.- Если блок
finally
завершается внезапно для разума S, то операторtry
совершает внезапно по причине S (и причина R отбрасывается).
Спецификация для return
действительно делает это явным:
ReturnStatement: return Expression(opt) ;
A
return
безExpression
пытается передать управление вызывающему методу или конструктору, который его содержит.A
return
с помощьюExpression
попыток передать управление вызывающему методу, который содержит его; значениеExpression
становится значением вызова метода.В предыдущих описаниях говорится, что " пытается передать управление", а не просто "передает управление", потому что, если в методе или конструкторе есть какие-либо
try
-операторы, чьи блокиtry
содержатreturn
, то любые предложенияfinally
этих операторовtry
будут выполняться, чтобы быть наиболее внутренним до внешнего, до того как управление будет передано вызову метода или конструктора. Резкое завершение предложенияfinally
может нарушить передачу управления, инициированного операторомreturn
.
В дополнение к другим ответам важно указать, что "finally" имеет право переопределить любое исключение/возвращаемое значение блоком try..catch. Например, следующий код возвращает 12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
Аналогично, следующий метод не генерирует исключения:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
В то время как следующий метод делает это:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
OutOfMemoryError
? ;)
Я попробовал приведенный выше пример с небольшой модификацией -
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.");
}
}
Вышеупомянутый код выводит:
наконец, возвращает козыри.
2
Это происходит потому, что при выполнении return i;
i
имеет значение 2. После этого выполняется блок finally
, где 12 назначается i
, а затем выполняется System.out
out.
После выполнения блока finally
блок try
возвращает 2, а не возвращает 12, потому что этот оператор возврата не выполняется снова.
Если вы отлаживаете этот код в Eclipse, вы почувствуете, что после выполнения System.out
of finally
блокирует оператор return
блока try
выполняется снова. Но это не так. Он просто возвращает значение 2.
i
был не примитивом, а объектом Integer.
Вот разработка ответа Кевина. Важно знать, что возвращаемое выражение оценивается до finally
, даже если оно возвращается после.
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
}
}
Вывод:
X
finally trumps return... sort of
0
Вот и вся идея окончательного блока. Он позволяет вам убедиться, что вы выполняете очистку, которая в противном случае может быть пропущена, потому что вы, конечно же, возвращаетесь, между прочим.
Наконец, вызывается независимо от того, что происходит в блоке try (если вы не вызываете System.exit(int)
или виртуальная машина Java не запускается по какой-либо другой причине).
Логический способ подумать об этом:
Также возвращение в итоге выкинет любое исключение. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
наконец, всегда выполняется, если нет ненормального завершения программы (например, вызов System.exit(0)..). поэтому ваш sysout будет напечатан
Нет, не всегда один случай исключения //System.exit(0); прежде чем блок finally предотвратит, наконец, выполнение.
class A {
public static void main(String args[]){
DataInputStream cin = new DataInputStream(System.in);
try{
int i=Integer.parseInt(cin.readLine());
}catch(ArithmeticException e){
}catch(Exception e){
System.exit(0);//Program terminates before executing finally block
}finally{
System.out.println("Won't be executed");
System.out.println("No error");
}
}
}
Блок finally всегда выполняется, если нет аномального завершения программы, вызванного сбоем JVM или вызовом System.exit(0)
.
Кроме того, любое значение, возвращаемое из блока finally, переопределит значение, возвращаемое до выполнения блока finally, поэтому будьте осторожны при проверке всех точек выхода при окончательном использовании try.
Наконец, всегда выполняется, что вся точка, только потому, что она появляется в коде после возврата, не означает, что это было реализовано. Среда выполнения Java несет ответственность за запуск этого кода при выходе из блока try
.
Например, если у вас есть следующее:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
Среда выполнения создаст что-то вроде этого:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Если вызывается неперехваченное исключение, будет выполняться блок finally
, и исключение будет продолжать распространяться.
Это связано с тем, что вы назначили значение я как 12, но не возвращали значение я в функцию. Правильный код выглядит следующим образом:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Ответ прост ДА.
INPUT:
try{
int divideByZeroException = 5 / 0;
} catch (Exception e){
System.out.println("catch");
return; // also tried with break; in switch-case, got same output
} finally {
System.out.println("finally");
}
ВЫВОД:
catch
finally
Вкратце, в официальной документации Java (нажмите здесь), написано, что -
Если JVM завершает работу, пока выполняется код try или catch, тогда блок finally может не выполняться. Аналогично, если выполнение потока код try или catch прерывается или убивается, блок finally может не выполняются, даже если приложение в целом продолжается.
Поскольку блок finally всегда будет вызываться, если вы не вызываете System.exit()
(или поток не работает).
Да, он будет вызван. Это весь смысл наличия ключевого слова finally. Если выпрыгнуть из блока try/catch можно просто пропустить блок finally, это было бы то же самое, что и поставить System.out.println вне try/catch.
Да, блок finally всегда выполняется. Большинство разработчиков используют этот блок для закрытия соединения с базой данных, объекта результатов, объекта-оператора и также использования в спящем режиме java для отката транзакции.
Да, будет. Только в случае, если это не произойдет, JVM выйдет или сработает
Да, будет. Независимо от того, что происходит в вашем блоке try или catch, если иное не вызвано вызовом System.exit() или JVM. если в блоке (-ах) есть какой-либо оператор возврата, он, наконец, будет выполнен до этого оператора return.
Рассмотрим следующую программу:
public class SomeTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
Начиная с Java 1.8.162, приведенный выше блок кода дает следующий вывод:
-abc-
---AGAIN---
-abc-xyz-abc-
это означает, что использование finally
для освобождения объектов является хорошей практикой, подобной следующему коду:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null;
}
}
sb.setLength(0)
это не должно быть sb.setLength(0)
в наконец?
То, что на самом деле истинно на любом языке..., наконец, всегда будет выполняться перед оператором return, независимо от того, где это возвращение находится в теле метода. Если бы это было не так, блок finally не имел бы большого значения.
finally
на первом месте ...
В дополнение к вопросу о возврате в окончательной замене возврата в блоке try то же самое относится к исключению. Блок finally, который генерирует исключение, заменит возврат или исключение, вызванное из блока try.
try
- catch
- finally
являются ключевыми словами для использования случая обработки исключений.
Как нормальное объяснение
try {
//code statements
//exception thrown here
//lines not reached if exception thrown
} catch (Exception e) {
//lines reached only when exception is thrown
} finally {
// always executed when the try block is exited
//independent of an exception thrown or not
}
Блок finally предотвращает выполнение...
System.exit(0);
Добавляем к @vibhash answer, поскольку никакой другой ответ не объясняет, что происходит в случае изменяемого объекта, такого как ниже.
public static void main(String[] args) {
System.out.println(test().toString());
}
public static StringBuffer test() {
StringBuffer s = new StringBuffer();
try {
s.append("sb");
return s;
} finally {
s.append("updated ");
}
}
Выведет
sbupdated
Да, потому что без оператора управления может предотвратить выполнение finally
.
Вот пример ссылки, где будут выполняться все блоки кода:
| x | Current result | Code
|---|----------------|------ - - -
| | |
| | | public static int finallyTest() {
| 3 | | int x = 3;
| | | try {
| | | try {
| 4 | | x++;
| 4 | return 4 | return x;
| | | } finally {
| 3 | | x--;
| 3 | throw | throw new RuntimeException("Ahh!");
| | | }
| | | } catch (RuntimeException e) {
| 4 | return 4 | return ++x;
| | | } finally {
| 3 | | x--;
| | | }
| | | }
| | |
|---|----------------|------ - - -
| | Result: 4 |
В следующем варианте return x;
будет пропущен. Результат по-прежнему 4
:
public static int finallyTest() {
int x = 3;
try {
try {
x++;
if (true) throw new RuntimeException("Ahh!");
return x; // skipped
} finally {
x--;
}
} catch (RuntimeException e) {
return ++x;
} finally {
x--;
}
}
Ссылки, конечно, отслеживают их статус. В этом примере возвращается ссылка с помощью value = 4
:
static class IntRef { public int value; }
public static IntRef finallyTest() {
IntRef x = new IntRef();
x.value = 3;
try {
return x;
} finally {
x.value++; // will be tracked even after return
}
}
Логический способ подумать об этом:
Код, помещенный в блок finally, должен быть выполнен независимо от того, что происходит в блоке try.
Итак, если код в блоке try пытается вернуть значение или выбросить исключение, элемент будет помещен 'на полку, пока блок finally не сможет выполнить Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или бросать все, что ему нравится. В этом случае все, что осталось на полке, отбрасывается.
Единственным исключением является то, что VM полностью отключается во время блока try, например. по 'System.exit
Никогда не бросайте исключение из блока finally
try {
someMethod(); //Throws exceptionOne
} finally {
cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever
}
Это прекрасно, если cleanUp() никогда не может вызвать каких-либо исключений. В приведенном выше примере, если someMethod() выдает исключение, а в блоке finally также очищает исключение, то второе исключение выйдет из метода, и исходное первое исключение (правильная причина) будет потеряно навсегда. Если код, который вы вызываете в блоке finally, может вызвать исключение, убедитесь, что вы либо обрабатываете его, либо регистрируете его. Никогда не позволяйте этому выходить из блока finally.
Фактически выход из программы (либо путем вызова System.exit(), либо путем возникновения фатальной ошибки, из-за которой процесс прерывается: иногда его называют неофициально "горячей точкой" или "доктором Уотсоном" в Windows) блок от выполнения!
Нет ничего, что могло бы помешать нам вложить блоки try/catch/finally (например, поставить блок try/finally внутри блока try/catch или наоборот), и это не такая необычная вещь.
finally
будет выполняться, и это точно.
finally
не будет выполняться в следующих случаях:
случай 1:
Когда вы выполняете System.exit()
.
случай 2:
При сбое вашего JVM/Thread.
случай 3:
Когда ваше выполнение остановлено между вручную.
Наконец, блок всегда выполняет ли дескриптор исключений или нет. Если какое-либо исключение произошло до того, как попытаться выполнить блок, то окончательный блок не будет выполняться.
Если генерируется исключение, оно, наконец, запускается. Если исключение не выбрасывается, оно, наконец, запускается. Если исключение поймано, он, наконец, запускается. Если исключение не поймано, он, наконец, запускается.
Только время, когда он не запускается, - это когда JVM завершает работу.
Рассмотрим это в обычном ходе выполнения (т.е. без какого-либо исключения): если метод не является "void", он всегда явно возвращает что-то, но, наконец, всегда выполняется
Потому что окончательный всегда вызывается в любых случаях, которые у вас есть. У вас нет исключения, оно все еще называется catch catch, оно все еще называется
Да, написано здесь
Если JVM завершает работу, пока выполняется код try или catch, блок finally может не выполняться. Аналогично, если поток, выполняющий код try или catch, прерывается или убивается, блок finally может не выполняться, даже если приложение в целом продолжается.
Блок finally не будет вызываться после возврата в нескольких уникальных сценариях: если сначала вызывается System.exit(), или если JVM аварийно завершает работу.
Позвольте мне попытаться ответить на ваш вопрос самым простым способом.
Правило 1: блок finally всегда запускается (Хотя есть исключения из этого, но пусть будет придерживаться этого на некоторое время.)
Правило 2: инструкции в блоке finally запускаются, когда элемент управления оставляет попытку или блок catch. Передача элемента управления может произойти в результате нормального выполнения, выполнения прерывания, продолжения, goto или оператор return, или пропозиция исключения.
В случае оператора return (с его заголовка) элемент управления должен покинуть вызывающий метод, и, следовательно, вызывает блок finally соответствующей структуры try-finally. Оператор return выполняется после блока finally.
В случае, если в блоке finally также есть оператор return, он определенно переопределит тот, который ожидает от блока try, поскольку он очищает стек вызовов.
Здесь вы можете найти лучшее объяснение: http://msdn.microsoft.com/en-us/.... концепция в основном одинакова на всех языках высокого уровня.
Если вы не обрабатываете исключение, перед завершением программы JVM выполняет окончательный блок. Он не будет выполняться только в том случае, если нормальное выполнение программы не будет означать прекращение программы из-за следующих причин.
Вызывая фатальную ошибку, которая приводит к прерыванию процесса.
Прекращение программы из-за повреждения памяти.
Вызовите System.exit()
Если программа переходит в бесконечный цикл.
Я попробовал это, это однопоточный.
class Test {
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Основной поток будет находиться в состоянии ожидания навсегда, поэтому, наконец, никогда не будет вызван,
поэтому консольный вывод не будет печатать строку: after wait()
или finally
Согласившись с @Stephen C, приведенный выше пример является одним из упоминаний о 3-м случае здесь: https://stackoverflow.com/questions/65035/does-a-finally-block-always-get-executed-in-java
Добавим еще несколько таких возможностей бесконечного цикла в следующем коде:
// import java.util.concurrent.Semaphore;
class Test {
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Случай 2: если JVM аварийно завершает работу
import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Test {
public static void main(String args[]) {
try {
unsafeMethod();
// Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
}
Ссылка: как вы разбили JVM?
Случай 6: если блок finally будет выполняться потоком демона, и все остальные потоки, не являющиеся демонами, завершат работу до вызова finally.
class Test {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
}
вывод: Это не выводит "finally", что означает, что "блок finally" в "потоке демона" не был выполнен
main Thread Printing Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED Thread :Thread[main,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:3 ------------------------------------------------- Daemon Thread printing Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:2 ------------------------------------------------- Process finished with exit code 0
Спецификация языка Java описывает, как блоки try-catch-finally и try-catch работают в 14.20.2
Ни в каком месте это не указывает, что блок finally всегда выполняется. Но для всех случаев, в которых завершаются блоки try-catch-finally и try-finally, указывается, что перед выполнением должны быть выполнены, наконец, finally.
try {
CODE inside the try block
}
finally {
FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).
JLS не гарантирует, что FIN выполняется после CODE. JLS гарантирует, что если выполняются CODE и NEXT, то FIN всегда будет выполняться после CODE и до NEXT.
Почему JLS не гарантирует, что блок finally всегда выполняется после блока try? Потому что это невозможно. Маловероятно, но возможно, что JVM будет прервана (kill, crash, power off) сразу после завершения блока try, но перед выполнением блока finally. JLS ничего не может сделать, чтобы избежать этого.
Таким образом, любое программное обеспечение, для которого его правильное поведение зависит от блоков finally, всегда выполняющихся после того, как завершены их блоки try.
Возвраты в блоке try не имеют отношения к этой проблеме. Если выполнение достигает кода после try-catch-finally, гарантируется, что блок finally будет выполнен раньше, с возвратами внутри блока try или без него.
Попробуйте этот код, вы поймете, что код в блоке finally выполняется после оператора return.
public class TestTryCatchFinally {
static int x = 0;
public static void main(String[] args){
System.out.println(f1() );
System.out.println(f2() );
}
public static int f1(){
try{
x = 1;
return x;
}finally{
x = 2;
}
}
public static int f2(){
return x;
}
}
Да, он всегда будет вызываться, но в одной ситуации он не вызывается, когда вы используете System.exit()
try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
То же самое со следующим кодом:
static int f() {
while (true) {
try {
return 1;
} finally {
break;
}
}
return 2;
}
f вернет 2!
наконец, можно также выйти преждевременно, если исключение выбрано внутри вложенного блока finally. Компилятор предупредит вас, что блок finally не завершится нормально или сообщит об ошибке, что у вас недоступен код. Ошибка для недостижимого кода будет показана только в том случае, если бросок не находится за условным выражением или внутри цикла.
try{
}finally{
try{
}finally{
//if(someCondition) --> no error because of unreachable code
throw new RunTimeException();
}
int a = 5;//unreachable code
}
Я был очень смущен всеми ответами, представленными на разных форумах, и решил окончательно закодировать и посмотреть. Вывод:
, наконец, будет выполнен, даже если в блоке try и catch есть возврат.
try {
System.out.println("try");
return;
//int i =5/0;
//System.exit(0 ) ;
} catch (Exception e) {
System.out.println("catch");
return;
//int i =5/0;
//System.exit(0 ) ;
} finally {
System.out.println("Print me FINALLY");
}
Выход
попробовать
Напечатайте меня НАКОНЕЦ
System.exit(0)
в try и catch block в приведенном выше коде, и по какой-либо причине перед ним возникает исключение.Наконец, он всегда называется в конце
когда вы пытаетесь, он выполняет некоторый код, если что-то происходит в try, тогда catch поймает это исключение, и вы можете напечатать некоторый mssg или выбросить ошибку, а затем, наконец, будет выполнен блок.
Наконец, обычно используется при очистке, например, если вы используете сканер в java, вероятно, вы должны закрыть сканер, поскольку это приводит к другим проблемам, таким как невозможность открыть какой-либо файл
finally выполняется всегда, даже если вы поместите оператор return в блок try. Блок finally будет выполнен перед оператором return.
Я хотел бы поделиться вами, код в блоке finally будет почти всегда выполняться.
Для полноты, если блок finally выполняет возврат в то время как неперехваченное исключение находится в ожидании, исключение заглушается; то есть он просто исчезает.
попробовать {
рискованный блок кода
} catch (ExceptionClassName exceptionObjectName) {
код для решения проблемы
} наконец {
код, который всегда будет выполнять
}
окончательно блокировать выполнение всегда, независимо от объекта исключения, или нет.
есть две возможности остановить блок finally: 1. выражение о возврате. 2. System.exit(0);
public class test{
public static void main(String[] args){
if(true) {
return;
}
try{
System.out.println(1);
return;
Да, в блоке try/catch/finally
окончательно будет вызываться.
Однако в вашем примере:
try {
something();
return success; // Will return out of the method if successful.
} catch (Exception ex) {
return failure; // Will return out of the method if not successful.
} finally {
// Possibly unreachable code.
System.out.println("I'm not sure if this will be printed...");
}
Ваш finally
может не выполняться из-за операторов return
.
Теперь, в зависимости от обстоятельств кода, достаточно всего одного оператора return
и передать переменную.
public boolean runSomething () {
boolean isSuccess = true;
try {
something(); // Runs thread. If successful, run finally block.
} catch (Exception ex) {
// If exception is caught, display (if desired) exception and set
// the out bound variable to false. Finally, run finally block.
System.out.println("Exception: " + ex.toString());
isSuccess = false;
} finally {
System.out.println("This was executed in the finally.");
}
return isSuccess; // Returns success flag.
}
Я понимаю, что этой должности 5 лет, но я надеюсь, что это поможет кому-то! Ура!