Понимание try catch finally с return и значением, которое он возвращает
у меня есть следующий фрагмент кода.
public static void main(String[] args) {
System.out.println(returnString());
}
private static String returnString(){
try {
System.out.println("Executing try");
return "Return try value";
} catch (Exception e){
System.out.println("Executing Catch");
return "Return catch value";
} finally {
System.out.println("Executing finally");
return "Return finally value";
}
}
выход для этого
Executing try
Executing finally
Return finally value
если я изменю свой блок finally, чтобы не возвращать ничего подобного
public static void main(String[] args) {
System.out.println(returnString());
}
private static String returnString(){
try {
System.out.println("Executing try");
return "Return try value";
} catch (Exception e){
System.out.println("Executing Catch");
return "Return catch value";
} finally {
System.out.println("Executing finally");
}
}
тогда выход
Executing try
Executing finally
Return try value
теперь я понимаю, что, наконец, всегда выполняется, за исключением случаев вызова системы.выход (0); вызывается или JVM аварийно завершает работу.
Что я не могу понять, так это почему возвращаемое значение изменилось ? Я все равно ожидаю, что он вернет значение try блок.
может ли кто-нибудь объяснить, почему значение finally учитывается, а не возвращаемое значение из блока try ?
пожалуйста, воздержитесь от ответа, потому что, наконец, выполняется, даже если есть возврат в блоке try ... или, наконец, не выполняется, только если есть система.выход (0); вызывается или JVM аварийно завершает работу. насколько я знаю.
EDIT:
(согласно Кортик комментировать этой)
public static void main(String[] args) {
System.out.println(returnString());
}
private static String returnString(){
try {
System.out.println("Executing try");
return printString("Return try value");
} catch (Exception e){
System.out.println("Executing Catch");
return printString("Return catch value");
} finally {
System.out.println("Executing finally");
return printString("Return finally value");
}
}
private static String printString(String str){
System.out.println(str);
return str;
}
выход:
Executing try
Return try value
Executing finally
Return finally value
Return finally value
3 ответов
непосредственно перед возвращением из основного блока JVM должен убедиться, что finally
блок выполняется, поэтому он делает это. Идея состоит в том, чтобы выполнить finally
блок, а затем вернуться и выполнить return
оператор из основного блока. Но если у вас есть return
заявление в finally
блок, тогда он будет выполнен, когда finally
блок выполняется... это означает, что элемент управления никогда не возвращается в основной блок для завершения return
заявление.
- в JVM встречает
return
оператор в основном блоке. Он приостанавливает выполнение основного блока и проверяетfinally
предложения. - выполняет
finally
предложение в полном объеме, включая егоreturn
заявление. - он никогда таким образом не получает, чтобы завершить
try
блок.
обратите внимание, однако, что try
блока return
выражение оценивается а потом выбрасывают. Это важно, если у него есть побочные эффекты. Так что если ваш main блок return i++
тогда это не повлияет на возвращаемое значение, но i
по-прежнему будет увеличиваться. (Спасибо Кортик за указание на это.)
если у вас есть вернуться в конце концов, это окончательное возвращение.
это неудивительно. Это реальное поведение. Возвращая решил по finally
заблокировать.
Если вы ничего не возвращаете в конце концов, то Предыдущее значение будет возвращаемым значением - возвращаемое значение (в вашем случае значение блока try).
независимо от того, что вы делаете в try
блок finally всегда выполняется, даже если вы возврат из блока try (если у вас есть return in finally, это окончательное возвращение).
С finally
docs
система выполнения всегда выполняет операторы в блоке finally независимо от что происходит в блоке try. Так что это идеальное место для уборки.
Примечание: наконец, предназначен для очистки.
в Java, код:
try {
if (foo()) return 1;
} catch (Exception e){
if (goo()) return 2;
} finally {
if (moo()) return 3;
}
будет переписан компилятором в:
try {
if (foo())
{
if (moo()) return 3; // Finally code executed before return
return 1;
}
} catch (Exception e){
if (goo())
{
if (moo()) return 3; // Finally code executed before return
return 2;
}
} catch (Throwable e){
if (moo()) return 3; // Finally code executed before re-throw
throw e;
}
if (moo()) return 3; // Finally code executed before leaving block
в принципе, компилятор будет дублировать код в тег finally
блок точно один раз в каждом пути выполнения, который заставит выполнение кода покинуть охраняемый блок, будь то через return
, throw
, или проваливается. Обратите внимание, что в то время как некоторые языки запрещают return
внутри a finally
блок, Java не делает; если finally
блок выполнен в виде следствием исключения, однако, a return
внутри блока может привести к тому, что исключение будет молча оставлено (посмотрите на код выше с пометкой "наконец-то код выполнен перед повторным броском"; если return 3;
выполняется, повторный бросок будет пропущен).