Пояснение пробок-окончательного возврата
Прочитав все вопросы, заданные на этом форуме, связанные с темой выше (см. заголовок), я полностью понимаю, что finally
всегда называется. (кроме System.exit
и бесконечных циклов). Однако я хотел бы знать, вызывается ли return
в блоке catch, а затем из блока finally вызывается другой return
.
Например:
public static void main(String[]args) {
int a = new TestClass().absorbeTheValue();
}
int absorbeTheValue() {
try {
int a = 10/0;
if (a > 0) return 4;
} catch(Exception e) {
return 45;
} finally {
return 34;
}
}
Таким образом, вывод (когда будет вызван метод) будет в любом случае 34. Это означает, что, наконец, всегда запускается. Я думаю, что другие "возвращения" вообще не запускаются. Во многих сообщениях я обнаружил, что, наконец, напишу содержимое по тому, что уже было написано в результате возврата catch. Я понимаю, что как только возвращаемое значение в предложении catch должно быть оценено, поток управления переходит к предложению finally, которое, в свою очередь, возвращает другое, на этот раз результат будет оцениваться без передачи управления обратно в предложение catch, Таким образом, только return
, вызываемый во время выполнения, будет окончательным возвратом. Вы согласны с этим?
A return
в finally
не возвращает элемент управления программе, но возвращает значение и завершает метод. Можем ли мы так сказать?
Ответы
Ответ 1
Если достигнут return
в блоке try
, он передает управление блоку finally
, и функция в конечном итоге возвращается нормально (а не бросок).
Если возникает исключение, но затем код достигает return
из блока catch
, управление передается блоку finally
, и функция в конечном итоге возвращает нормально (а не бросок).
В вашем примере у вас есть return
в finally
, поэтому независимо от того, что произойдет, функция вернет 34
, потому что finally
имеет окончательное (если хотите) слово.
Хотя это не относится к вашему примеру, это было бы правдой, даже если у вас не было catch
, и если исключение было выбрано в блоке try
и не было обнаружено. Выполняя return
из блока finally
, вы полностью исключаете исключение. Рассмотрим:
public class FinallyReturn {
public static final void main(String[] args) {
System.out.println(foo(args));
}
private static int foo(String[] args) {
try {
int n = Integer.parseInt(args[0]);
return n;
}
finally {
return 42;
}
}
}
Если вы запустите это без предоставления каких-либо аргументов:
$ java FinallyReturn
... код в foo
выдает ArrayIndexOutOfBoundsException
. Но поскольку блок finally
выполняет return
, это исключение блокируется.
Это одна из причин, почему лучше избегать использования return
в finally
.
Ответ 2
Вот какой код, который показывает, как он работает.
class Test
{
public static void main(String args[])
{
System.out.println(Test.test());
}
public static String test()
{
try {
System.out.println("try");
throw new Exception();
} catch(Exception e) {
System.out.println("catch");
return "return";
} finally {
System.out.println("finally");
return "return in finally";
}
}
}
Результаты:
try
catch
finally
return in finally