Учитывая этот код, могу ли я быть абсолютно уверен, что блок 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");
}
Эффективная Java говорит иначе informit.com/articles/article.aspx?p=1216151&seqNum=7
@BinoyBabu, финализатор! = finally; финализатор == метод finalize().
@Boann Правильно, «не всегда». Но тогда вы можете использовать никогда и никогда слова «гарантировано» или «всегда».
@Boann Я бы сказал так: поток выполнения всегда проходит окончательно, прежде чем он ускользнет из структуры try-finally. Если он умирает внутри, меня это устраивает, потому что основная цель finally - убедиться, что что-то не испортилось для других частей кода.
Похоже, вы там неплохо поймали!
Если блок finally возвращает значение, то блок try / catch не может вернуться.




Да, finally будет вызываться после выполнения кодовых блоков try или catch.
finally не будет вызван только в следующих случаях:
System.exit()Runtime.getRuntime().halt(exitStatus)try или catchkill -9 <pid> в UNIXfinally будет выполняться потоком демона, а все другие потоки, не являющиеся демонами, завершаются до вызова finallyНа самом деле thread.stop() не обязательно предотвращает выполнение блока finally.
Как насчет того, чтобы сказать, что блок finally будет называться после блоком try, а управление перед переходит к следующим операторам. Это согласуется с блоком try, включающим бесконечный цикл, и, следовательно, блок finally никогда не вызывается.
Согласно определению @andrzejDoyle, он сначала вернет success, прежде чем перейти к блоку finally. Это верно?
@dieend: он решит, что возвращаемое значение будет успешным, выполнит блок finally, а затем вернет управление вызывающей функции. Ничего не будет возвращено, если блок finally сработает.
есть еще один случай, когда мы используем вложенные блоки попробовать-поймать-наконец
Кроме того, блок finally не вызывается в случае возникновения исключения потоком демона.
Но эффективная Java говорит об обратном. informit.com/articles/article.aspx?p=1216151&seqNum=7
Это довольно интересно, что, наконец, будет вызвано, когда кто-то повторно выбрасывает свое исключение в catch () как новое исключение RuntimeException.
@BinoyBabu - Это про финализатор, а не окончательный блок
А что насчет Время выполнения # остановка?
@AmrishPandey "блок finally не вызывается в случае исключения, сгенерированного потоком демона" - правда ?? [Требуется цитата], я думаю?
@SusanW javarevisited.blogspot.in/2012/03/…
@SusanW docs.oracle.com/javase/tutorial/essential/exceptions/…
@AmrishPandey На странице Oracle демоны вообще не упоминаются. Другая страница (блоггера) обсуждает JVM прекращение, но не демонстрирует каких-либо различий по сравнению с потоком, не являющимся демоном. Реальность такова: при завершении System.exit (включая перехватчики выключения) или другом завершении все потоки просто умирают на том месте, где они стоят, будь то демон или нет: в любом случае окончательные операции не выполняются. Блогер ошибается, когда замечает это как разницу ... попробуйте сами.
@SusanW - Верно. Причина, по которой поток демона не выполняет finally в этом примере, - это причина 3). Это бесконечный цикл. Если цикла не было, то он также мог не выполнить finally по причине 1). Когда метод main возвращается (и нет потоков, не являющихся демонами), он выполняет System.exit() ... или эквивалент. Итог: потоки демонов НЕ являются исключением из причин, указанных в ответе выше.
Бесконечный цикл на самом деле не является исключением из правила «окончательно будет вызываться при завершении блока попытки». Даже с бесконечным циклом в блоке try, блок finally все еще буду выполняет когда завершится блок попыток, как обычно - блок try просто не завершается. Это не особый случай.
«Хост-система умирает; например, сбой питания, аппаратная ошибка ...» также не является исключением из правила окончательного блока. Это похоже на "будет ли return 1+1 всегда возвращать 2?" «Не обязательно; потеря питания может помешать return 1+1 вернуться 2.» ... не совсем часть ответа. То же самое с №4, пример kill -9; для №4 и №5 достаточно, чтобы был указан №2 «Сбой JVM», который можно было бы сформулировать так: «JVM завершает работу внезапно», чтобы лучше отловить все ситуации.
finally также выполняется, когда выбрасывается StackOverflowError.
Java System.exit(); (например, C# или PHP) может сбивать с толку разработчиков, пришедших с других языков программирования. В Python sys.exit() вызывает (обычное) исключение SystemExit, которое можно перехватить. В Паскале exit - это обычный управляющий оператор, и finally тоже будет выполняться.
@MCEmperor, чтобы воспользоваться этим, хотя finally выполняется даже после StackOverflowError, кадры, добавленные в стек в блоке finally, могут вызвать неожиданный дополнительныйStackOverflowError, что приведет к пропуску оставшегося содержимого блока finally. По этой причине ошибки StackOverflowError могут быть довольно опасными. Недавно мы столкнулись с трудной проблемой, когда семафоры не выпускались в блоке finally именно по этой причине.
В: Всегда ли? A: Да, за исключением ... Для меня это означает, что принятый ответ должен быть отрицательным. Если есть исключения из всегда, то их нет. Он может работать большую часть времени. Но не всегда. Я удивлен, что я один из немногих, кто отреагировал на это.
@JugsteR Все случаи, когда этого не происходит, - это когда происходит что-то сумасшедшее, например, когда кто-то принудительно убивает процесс, он входит в бесконечный цикл или отключение питания. Для меня, если он ведет себя определенным образом, за исключением самых крайних случаев, можно сказать «да, всегда, кроме…» вместо «нет». Фактически, в случае бесконечного цикла бы все еще выполняет finally, просто он никогда не заканчивает то, что делает до него.
Если машина приостановлена. Если ядро больше никогда не дает JVM время для выполнения. Вероятно, есть еще много крайних случаев, когда finally не выполняется. Этот ответ дает хорошее и легкое для понимания объяснение. Но было бы проще и проще сказать «Если блок try или блок try-catch завершается, то выполняется блок finally». JLS использует тот же самый язык.
Еще один: когда я отлаживаю с помощью IntelliJ, если я отбрасываю кадр стека внутри блока try (который также имеет связанный блок finally), IntelliJ спрашивает меня, хочу ли я выполнить блок finally или нет. Я не уверен, что это стандартная функция отладчика Java или что-то, что IntelliJ разработал самостоятельно.
finally всегда выполняется, если нет аварийного завершения программы (например, вызов System.exit (0) ..). Итак, ваш sysout будет напечатан
Да, позвонят. В этом весь смысл ключевого слова finally. Если выпрыгивание из блока try / catch могло просто пропустить блок finally, это было то же самое, что поместить System.out.println вне try / catch.
Пример кода:
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
К вашему сведению: в C# поведение идентично, за исключением того факта, что замена оператора в предложении finally на return 2; не допускается (ошибка компилятора).
Вот важная деталь, о которой следует помнить: stackoverflow.com/a/20363941/2684342
ЕСЛИ ВЫ ДОБАВИЛИ БЛОК ЗАХВАТА, error: missing return statement
Вы даже можете добавить оператор return в сам блок finally, который затем переопределит предыдущее возвращаемое значение. Это также волшебным образом отбрасывает необработанные исключения. На этом этапе вам следует подумать о рефакторинге вашего кода.
Это не совсем доказывает, что козыри в конечном итоге возвращаются. Возвращаемое значение печатается из кода вызывающего абонента. Кажется, мало что доказывает.
@Trimtab, да, это только ответ на вопрос как заданный. Ответ Тристана поясняет, что возвращаемое значение оценивается, блок finally запускается, а затем управление возвращается вызывающей стороне.
Извините, но это демонстрация, а не доказательство. Это только доказательство, если вы можете показать, что этот пример всегда ведет себя таким образом на всех платформах Java, И что аналогичные примеры также всегда ведут себя таким образом.
Кстати, не по теме: я политически уверен, что этот оператор print будет стареть, как молоко.
На самом деле это верно для любого языка ... finally всегда будет выполняться перед оператором return, независимо от того, где этот return находится в теле метода. Если бы это было не так, блок finally не имел бы особого значения.
Блок finally всегда выполняется, если не происходит аварийного завершения программы, либо в результате сбоя JVM, либо в результате вызова System.exit(0).
Кроме того, любое значение, возвращаемое из блока finally, переопределит значение, возвращенное до выполнения блока finally, поэтому будьте осторожны при проверке всех точек выхода при использовании try finally.
Кроме того, несмотря на то, что это плохая практика, если в блоке finally есть оператор return, он будет превосходить любой другой возврат из обычного блока. То есть следующий блок вернет false:
try { return true; } finally { return false; }
То же самое с выдачей исключений из блока finally.
Это ДЕЙСТВИТЕЛЬНО плохая практика. См. stackoverflow.com/questions/48088/… для получения дополнительной информации о том, почему это плохо.
Согласовано. Возврат в finally {} игнорирует любое исключение, созданное в try {}. Страшный!
Несмотря ни на что, у меня всегда есть ТОЛЬКО ОДИН оператор return в моих методах (который находится в конце), ну, кроме void. Это то, чему меня учили в школе, и я думаю, что это тоже лучшая практика.
@ dominicbri7 Как вы думаете, почему это лучше? И почему должно быть иначе, если функция / метод недействительны?
По той же причине я НИКОГДА не использую goto в своих кодах на C++. Я думаю, что множественные возвраты затрудняют чтение и отладку (конечно, в очень простых случаях это не применимо). Я думаю, это просто личное предпочтение, и, в конце концов, вы можете добиться того же, используя любой из методов.
Я обычно использую несколько возвратов в исключительных случаях. Например, если (есть причина не продолжать) return;
Я интерпретирую блок finally как сокращение для написания одного и того же кода в конце каждого блока catch: `catch (Exc exc) {doSome (); } поймать (AnotherExc exc) {doSome (); }
@MCEmperor Не то же самое, потому что, как говорится в ответе, если в блоке finally есть оператор возврата, он переопределит оператор в блоке catch. Вы не можете этого сделать с catch.
@ MooBob42, должен делать это со встроенным finally
Приведен очень интересный пример.
Также возврат в finally отбрасывает любое исключение. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
Логичный способ подумать об этом:
Это просто «логический способ подумать об этом» или действительно так, как предполагается, что блок finally должен работать в соответствии со спецификациями? Здесь была бы очень интересна ссылка на ресурс Sun.
В дополнение к пункту о возврате при окончательной замене возврата в блоке try то же самое верно и для исключения. Блок finally, который генерирует исключение, заменяет возврат или исключение, выданное из блока try.
Я пробовал приведенный выше пример с небольшими изменениями -
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, где 12 назначается i, а затем выполняется System.out out.
После выполнения блока finally блок try возвращает 2, а не 12, потому что этот оператор возврата не выполняется снова.
Если вы будете отлаживать этот код в Eclipse, то у вас возникнет ощущение, что после выполнения System.out блока finally снова выполняется инструкция return блока try. Но это не так. Он просто возвращает значение 2.
Этот пример потрясающий, он добавляет то, что не упоминалось в десятках, наконец, связанных тем. Думаю, вряд ли кто-нибудь из разработчиков об этом узнает.
Что, если бы i был не примитивным, а целочисленным объектом.
Мне трудно понять этот случай. docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14 .17 говорит, что «Оператор возврата с выражением пытается передать управление вызывающей стороне метода или тела лямбда, которое его содержит .... Если оценка выражения завершается нормально, с получением значения V ..» Что я мог догадаться из этого оператора - кажется, что return не оценивает выражение снова после того, как оценивает значение V, поэтому измененный i не влияет на возвращаемое значение, поправьте меня.
Но я не смог найти никаких доказательств по этому поводу, где упоминается, что return не оценивает выражение снова.
@meexplorer немного опоздал, но это объясняется в JLS 14.20.2. Выполнение try-finally и try-catch-finally - сформулировано немного сложно, 14.17. Заявление о возврате также необходимо прочитать
@ Ямча Все равно было бы так же
Я считаю, что если вы добавили оператор return в блок finally, возвращаемое значение было бы 12, а не 2. Пример в основном показывает, что блок finally помещается в стек вызовов точно так же, как вызов метода - что делает локальный копия i, которая возвращается к 2 после выталкивания стека.
Наконец, всегда выполняется, в этом вся суть, просто потому, что он появляется в коде после возврата, не означает, что это реализовано именно так. Среда выполнения Java отвечает за запуск этого кода при выходе из блока try.
Например, если у вас есть следующее:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
Среда выполнения сгенерирует что-то вроде этого:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Если генерируется неперехваченное исключение, запускается блок finally, и исключение продолжает распространяться.
Потому что блок finally всегда будет вызываться, если вы не вызовете System.exit() (или поток не выйдет из строя).
В этом вся идея блока finally. Это позволяет вам убедиться, что вы выполняете очистку, которую в противном случае можно было бы пропустить из-за того, что вы вернетесь, среди прочего, конечно.
Наконец, в блоке try вызывается независимо от того, что происходит (пока не вы вызываете System.exit(int), или виртуальная машина Java отключается по какой-то другой причине).
Это очень слабый ответ. stackoverflow.com/a/65049/715269
Потому что финал всегда вызывается в любых случаях, которые у вас есть. У вас нет исключения, оно все еще вызывается, перехватывает исключение, оно все еще вызывается
В дополнение к другим ответам важно указать, что '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();
}
}
Следует отметить, что средний случай - это именно та причина, по которой наличие оператора return внутри блока finally абсолютно ужасно (оно может скрыть любой Throwable).
Кому не нужен OutOfMemoryError с подавлением? ;)
Я тестировал его, и он подавляет такую ошибку (ура!). Он также генерирует предупреждение, когда я его компилирую (ура!). И вы можете обойти это, определив возвращаемую переменную, а затем используя return retValпосле блок finally, хотя это, конечно, предполагает, что вы подавили некоторые другие исключения, потому что в противном случае код не имел бы смысла.
Рассмотрим это при нормальном ходе выполнения (то есть без какого-либо исключения): если метод не является `` недействительным '', тогда он всегда явно что-то возвращает, но, наконец, всегда выполняется
Это потому, что вы присвоили i значение 12, но не вернули значение i функции. Правильный код выглядит следующим образом:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Вот официальные слова из спецификации языка Java.
14.20.2. Выполнение try-finally и try-catch-finally
A
trystatement with afinallyblock is executed by first executing thetryblock. Then there is a choice:
- If execution of the
tryblock completes normally, [...]- If execution of the
tryblock completes abruptly because of athrowof a value V, [...]- If execution of the
tryblock completes abruptly for any other reason R, then thefinallyblock is executed. Then there is a choice:
- If the finally block completes normally, then the
trystatement completes abruptly for reason R.- If the
finallyblock completes abruptly for reason S, then thetrystatement completes abruptly for reason S (and reason R is discarded).
Спецификация return фактически делает это явным:
JLS 14.17 Заявление о возврате
ReturnStatement: return Expression(opt) ;A
returnstatement with noExpressionattempts to transfer control to the invoker of the method or constructor that contains it.A
returnstatement with anExpressionattempts to transfer control to the invoker of the method that contains it; the value of theExpressionbecomes the value of the method invocation.The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any
trystatements within the method or constructor whosetryblocks contain thereturnstatement, then anyfinallyclauses of thosetrystatements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of afinallyclause can disrupt the transfer of control initiated by areturnstatement.
Если выбрано исключение, функция finally выполняется. Если исключение не сгенерировано, функция finally выполняется. Если исключение обнаружено, наконец запускается. Если исключение не обнаружено, функция finally выполняется.
Он не запускается только тогда, когда JVM завершает работу.
Попробуйте этот код, вы поймете код в блоке finally выполняется после оператора возврата.
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 (0); до того, как блок finally предотвратит выполнение 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");
}
}
}
И это одна из причин, по которой вам действительно никогда не следует вызывать System.exit () ...
Да, это будет. Независимо от того, что происходит в вашем блоке try или catch, если только не вызывается System.exit () или JVM не аварийно завершается. если в блоке (ах) есть какой-либо оператор возврата, он будет выполнен до этого оператора возврата.
Вот разработка Ответ Кевина. Важно знать, что возвращаемое выражение оценивается до 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
Важно знать.
Полезно знать, и это тоже имеет смысл. Похоже, что на самом деле возвращаемое значение return - это то, что происходит после finally. Вычисление возвращаемого значения (здесь printX()) все еще предшествует этому.
Неа. Приведенный выше код должен заменить System.out.println("finally trumps return... sort of"); на System.out.print("finally trumps return in try"); return 42;.
Да, это будет. Только в том случае, если этого не произойдет, это выход из JVM или сбой
Блок finally всегда выполняется независимо от того, обрабатывается ли исключение или нет. Если какое-либо исключение произошло до блока try, блок finally не будет выполняться.
Вкратце, в официальной документации Java (щелкните здесь) написано, что -
If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
Да, блок finally всегда выполняется. Большинство разработчиков используют этот блок для закрытия соединения с базой данных, объекта набора результатов, объекта оператора, а также используют его в спящем режиме java для отката транзакции.
finally будет работать, и это точно.
finally не будет выполняться в следующих случаях:
Случай 1 :
Когда вы выполняете System.exit().
случай 2:
Когда ваша JVM / Thread аварийно завершает работу.
случай 3:
Когда ваше выполнение остановлено вручную.
Я был очень смущен всеми ответами, представленными на разных форумах, и решил наконец написать код и посмотреть. Выход:
finally будет выполняться, даже если в блоке 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");
}
Выход
try
Print me FINALLY
System.exit(0) в блоке try and catch в приведенном выше коде и перед ним возникает исключение по любой причине.Спецификация языка 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 не гарантирует, что ПЛАВНИК выполняется после КОД. JLS гарантирует, что если выполняются КОД и СЛЕДУЮЩИЙ, то ПЛАВНИК всегда будет выполняться после КОД и перед СЛЕДУЮЩИЙ.
Почему JLS не гарантирует, что блок finally всегда выполняется после блока try? Потому что это невозможно. Маловероятно, но возможно, что JVM будет прервана (уничтожение, сбой, отключение питания) сразу после завершения блока try, но до выполнения блока finally. JLS ничего не может сделать, чтобы этого избежать.
Таким образом, любое программное обеспечение, правильное поведение которого зависит от того, что блоки finally всегда выполняются после того, как их блоки try завершены, ошибаются.
Инструкции return в блоке try не имеют отношения к этой проблеме. Если выполнение достигает кода после try-catch-finally, гарантируется, что блок finally будет выполнен раньше, с инструкциями return внутри блока try или без них.
Я пробовал это, Он однопоточный.
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception ignored) {
} finally {
System.out.println("finally");
}
}
mainThread навсегда останется в состоянии wait, следовательно, finally никогда не будет называться,
поэтому вывод консоли не будет printString: после wait() или finally
Согласованный с @Stephen C, приведенный выше пример является одним из 3-го случая упоминания здесь:
Добавляем еще несколько таких возможностей бесконечного цикла в следующий код:
// import java.util.concurrent.Semaphore;
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 ignored) {
} finally {
System.out.println("finally");
}
}
Случай 2: Если сначала произойдет сбой JVM
import sun.misc.Unsafe;
import java.lang.reflect.Field;
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 будет выполняться демоном Thread, а все остальные, кроме демона, Threads завершат работу до вызова finally.
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
См. Принятый ответ. Это просто крайний случай «бесконечного цикла».
finally также может быть преждевременно завершен, если Exception является thrown внутри вложенный блок finally. Компилятор предупредит вас о том, что блок finally не завершается нормально, или выдаст ошибку о недоступности кода. Ошибка для недоступного кода будет отображаться только в том случае, если throw не находится за условным оператором или внутри цикла.
try{
}finally{
try{
}finally{
//if (someCondition) --> no error because of unreachable code
throw new RunTimeException();
}
int a = 5;//unreachable code
}
Просто замечу, что это совершенно нормальное поведение. Любой / весь код преждевременно завершается, если возникает исключение. Это ничем не отличается от исключения, созданного где-либо еще. В спецификации нет специального правила, которое гласит, что «исключения не могут использоваться внутри блока finally». Из-за этого я сначала даже неправильно понял ваш ответ и чуть не дал -1, пока не перечитал его пару раз.
Ну, а чем отдача отличается от броска? Если вы вернетесь, тогда блок должен вернуться, но в блоке finally возврат будет отложен, и есть какое-то странное исключение для возврата, поэтому неясно, обрабатывает ли finally throw обычным образом. Это основная причина, по которой я написал это тогда. Также добавление блока try или catch не будет препятствовать выполнению блока finally, поэтому, конечно же. можно ожидать, что когда вы добавляете блок finally, он все равно выполняется.
"Чем возврат отличается от броска?" В некотором смысле, ни один из которых здесь не имеет отношения. В блоке finally возврат не откладывается, или вы имели в виду, что возврат в блоке try откладывается до тех пор, пока не будет выполнен блок finally (в этом случае да, это правда)? В любом случае то же самое относится и к выброшенным исключениям. Независимо от того, что происходит в try, когда достигается конец try, управление переходит к finally, затем все те же правила применяются в finally (с любой попыткой / уловом внутри, наконец, работает, как обычно).
Я не говорю, что ваш ответ неправильный, бесполезный или что-то в этом роде. Технически это правильно. Я просто заметил, что описанное вами поведение не является нарушением правила try / finally, которое просто гласит: «Независимо от того, что происходит в try/catch, как только они будут выполнены, поток управления буду перейдет к блоку finally». Гарантия try / finally, по сути, не более чем , не меньше этого. Внутри любого блока, будь то try / catch / finally или иначе, вы можете вкладывать в него другие блоки try / catch / finally, как вы предлагаете. Действительно, некоторые люди об этом не подозревают.
То же самое со следующим кодом:
static int f() {
while (true) {
try {
return 1;
} finally {
break;
}
}
return 2;
}
f вернет 2!
Дублирующий ответ
Answer is simple YES.
ВХОД:
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
Ответ прост: НЕТ.
@ChristopheRoussy Как? Вы можете объяснить, пожалуйста?
прочтите принятый ответ, исходный вопрос касается «Всегда ли он будет выполняться», и так будет не всегда. В вашем случае это будет, но это не ответ на исходный вопрос и может даже ввести в заблуждение новичков.
тогда в каком случае он не будет выполнен?
Во всех случаях, упомянутых в других ответах, см. Принятый ответ с 1000+ голосами.
Да, он всегда будет вызываться, но в одной ситуации он не вызывается, когда вы используете 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.
}
Дублирующий ответ
Не только «дублирующий», но и противоречивый.
На этот вопрос ответили много раз, так какую новую информацию добавляет ваш ответ?
Если вы не обрабатываете исключение, перед завершением программы JVM выполняет блок finally. Он не будет выполнен только в том случае, если нормальное выполнение программы завершится неудачей, что означает завершение программы по следующим причинам:
Вызывая фатальную ошибку, приводящую к прерыванию процесса.
Завершение программы из-за повреждения памяти.
Вызывая System.exit ()
Если программа переходит в бесконечный цикл.
Блок finally не будет вызываться после возврата в нескольких уникальных сценариях: если сначала вызывается System.exit () или если JVM дает сбой.
Позвольте мне попытаться ответить на ваш вопрос как можно проще.
Правило 1: блок finally всегда выполняется (Хотя есть исключения из этого. Но давайте пока останемся на этом.)
Правило 2: операторы в блоке finally выполняются, когда управление выходит из блока try или catch. Передача управления может происходить в результате нормального выполнения, выполнения оператора break, continue, goto или return или распространения исключения.
В случае конкретного оператора return (поскольку он подписан) элемент управления должен покинуть вызывающий метод и, следовательно, вызывает блок finally соответствующей структуры try-finally. Оператор return выполняется после блока finally.
Если в блоке finally также есть оператор return, он определенно переопределит оператор, ожидающий в блоке try, поскольку он очищает стек вызовов.
Вы можете сослаться на лучшее объяснение здесь: http://msdn.microsoft.com/en-us/ .... концепция в основном одинакова для всех языков высокого уровня.
Да, потому что нет контрольного заявления может предотвратить выполнение 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
}
}
Да написано здесь
If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
Итак, когда вы говорите «да», вы имеете в виду «нет»?
Добавление к Ответ @ vibhash, поскольку никакой другой ответ не объясняет, что происходит в случае изменяемого объекта, подобного приведенному ниже.
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
Начиная с Java 1.8.162, это не результат.
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);Блок finally выполняется всегда, даже если вы поместите оператор return в блок try. Блок finally будет выполнен перед оператором 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());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
Начиная с Java 1.8.162, приведенный выше блок кода дает следующий результат:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
это означает, что использование finally для освобождения объектов является хорошей практикой, как и следующий код:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
Разве это не должно быть наконец-то sb.setLength(0)?
sb.setLength (0) просто очистит данные в StringBuffer. Итак, sb = null отсоединит объект от ссылки.
Разве «xyz» не следует печатать дважды на выходе? Поскольку функция вызывалась дважды, почему «finally» было только один раз?
@fresko: finallly определенно вызывается дважды, но когда дело доходит до вывода в консоли, он будет отображаться только один раз из-за оператора return. Вы можете запустить программу и увидеть результат, а после этого добавить еще один оператор System.out.println(sb.toString());.
Это не очень хорошая практика. Последний блок с sb = null; просто добавляет ненужный код. Я понимаю, что вы имеете в виду, что блок finally - хорошее место для освобождения ресурсов, таких как соединение с базой данных или что-то в этом роде, но имейте в виду, что ваш пример может запутать новичков.
@Samim Спасибо, я добавил строки System.out.println("---AGAIN2---");System.out.println(sb);, и теперь это более понятно. Как бы то ни было, вывод противоречил вашему тезису: p Я также добавил к вашему ответу, но редактирование должно быть принято модератором или кем-то в этом роде. В противном случае вы можете добавить их
Наконец, всегда вызывается в конце
когда вы пытаетесь, он выполняет некоторый код, если что-то происходит при попытке, тогда catch перехватит это исключение, и вы можете вывести какое-то сообщение mssg или выдать ошибку, затем выполняется блок finally.
Наконец, обычно используется при очистке, например, если вы используете сканер в java, вам, вероятно, следует закрыть сканер, поскольку это приводит к другим проблемам, таким как невозможность открыть какой-либо файл.
Вот некоторые условия, которые могут обойти блок finally:
Пример выхода последнего недемонического потока:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
Выход:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
finally выполняется всегда и перед возвратом (вычисленного) значения x.
System.out.println(foo());
....
int foo(){
int x = 2;
try{
return x++;
} finally{
System.out.println(x);
}
}
Выход:
3
2
Хороший наглядный пример, +1.
пример попытки с ресурсом
static class IamAutoCloseable implements AutoCloseable {
private final String name;
IamAutoCloseable(String name) {
this.name = name;
}
public void close() {
System.out.println(name);
}
}
@Test
public void withResourceFinally() {
try (IamAutoCloseable closeable1 = new IamAutoCloseable("closeable1");
IamAutoCloseable closeable2 = new IamAutoCloseable("closeable2")) {
System.out.println("try");
} finally {
System.out.println("finally");
}
}
Тестовый результат:
try
closeable2
closeable1
finally
В противном случае ключевое слово следует называть
probably.