try {
...
return qwe;
} catch {...}
finally {...}
Выполняется ли finally если в try есть return?
Ответы
Ответ 1
Конечно. На то он и finally. Правда результат может немного озадачить.
import java.util.*;
import java.lang.*;
class Main
{
public static int test() {
try {
System.out.println("test");
return 1;
}
finally {
System.out.println("fin");
return 2;
}
//return 3;
}
public static void main (String[] args) throws java.lang.Exception
{
int i = test();
System.out.println("test return " + i);
}
}
вывод будет такой:
test
fin
test return 2
а вот строку с return 3; не даст раскомментировать компилятор.
Ответ 2
Finlally выполняется почти всегда.
Update, хотел бы дополнить мой ответ по поводу обработки исключений в java.
Рассмотрим 3 случая, которые показались мне интересными. Вот метод testFinally()
static int testFinally() {
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
try {
if (i == 3) {
throw new Exception();
}
} catch (Exception e) {
System.out.println("Exception!");
return i;
} finally {
System.out.println("Finally ");
}
}
return -1;
}
В данных случае мы сможем увидеть что блок finally отрабатывает всегда, что и требовалось доказать.
Второй случае связан с многопточностью, вернее с тем фактом что, это правило также справедливо и для многопоточных приложений.
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Runnable(){
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread() + ": " + i);
TimeUnit.SECONDS.sleep(1);
}
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println("I'm in the finally block!");
}
}
});
t.start();
TimeUnit.SECONDS.sleep(5);
System.out.println("main() finished");
}
}
Тут тоже все будет правильно, то есть блок finally отработает.
Но не для потоков демонов. Как ни странно, джава прибьет их и не подавиться без выполнение блоков фанали.
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Runnable(){
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread() + ": " + i);
TimeUnit.SECONDS.sleep(1);
}
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println("I'm in the finally block!");
}
}
});
t.setDaemon(true);
t.start();
TimeUnit.SECONDS.sleep(5);
System.out.println("main() finished");
}
}
Что доказывает что везде есть исключения, даже в исключениях)
Ответ 3
В дополнение к существующим ответам привожу ссылки на соответствующие разделы документации.
Почему finally должен вызываться после return описано в спецификации языка Java в главах по return и finally:
14.17. The return Statement
...
A return statement with an Expression attempts to transfer control to the invoke
of the method or lambda body that contains it; the value of the Expression becomes th
value of the method invocation. More precisely, execution of such a return statemen
first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the return statement completes abruptly, the reason being a return with value V.
14.20.2. Execution of try-finally and try-catch-finally
...
If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and then there is a choice:
- If the finally block completes normally, then the try statement completes abruptly for reason R.
- If the finally block completes abruptly for reason S, then the try statemen
completes abruptly for reason S (and reason R is discarded).
Перевод:
14.17. Инструкция return
...
Инструкция return с выражением Expression пытается передать управление коду, вызвавшем
метод или лямбда-выражение, содержащее эту инструкцию; значение Expression становитс
значением вызова метода. Говоря более строго, выполнение такой инструкции return сначал
вычисляет Expression. Если вычисление Expression завершается преждевременно по некоторой причине, инструкция return завершается преждевременно по той же самой причине. Если вычисление Expression завершается нормально, давая значение V, то инструкция return завершается преждевременно по той причине, что она является возвратом значения V
14.20.2. Выполнение try-finally и try-catch-finally
...
Если выполнение блока try завершается преждевременно по некоторой иной причин
R, выполняется блок finally. Далее возможны следующие варианты.
- Если блок finally завершается нормально, то инструкция try завершается преждевременно по причине R.
- Если блок finally завершается преждевеременно S, инструкция try завершается преждевременно по причине S (причина R игнорируется).
Если коротко, то вызов return — частный случай преждевременного завершения, при это
преждевременное завершение из finally перекрывает и отбрасывает любое преждевременное завершение в блоке try.
Если в блоке try будет выброшено исключение, которое не будет поймано ни одним и
блоков catch (если они есть), то оно будет отброшено и забыто при вызове return, либо при выбрасывании нового исключения в finally.
Ответ 4
В дополнение к предыдущим ответам добавлю, на мой взгляд, самый наглядный. Здес
второй return в блоке finally перекрывает первый.
Взято здесь: https://programming.guide/java/try-finally.html
Комментариев нет:
Отправить комментарий