Выполняется ли окончательно на Java?

Учитывая этот код, могу ли я быть абсолютно уверенным, что блок finally всегда выполняется, вне зависимости от того, something() что- something() ?

 try { something(); return success; } catch (Exception e) { return failure; } finally { System.out.println("i don't know if this will get printed out."); } 

30 Solutions collect form web for “Выполняется ли окончательно на Java?”

Да, finally , вызывается после выполнения блоков try или catch.

Единственными моментами, которые, finally , не будут называться, являются:

  1. Если вы вызываете System.exit() ;
  2. Если сначала произойдет сбой JVM;
  3. Если JVM достигает бесконечного цикла (или другого не прерывающегося, не заканчивающегося оператора) в блоке try или catch ;
  4. Если ОС принудительно завершает процесс JVM; например, «kill -9» в UNIX.
  5. Если хост-система умирает; например, сбой питания, аппаратная ошибка, паника ОС и т. д.
  6. Если, наконец, блок будет выполняться streamом демона, а все остальные не-демонные streamи выходят до того, как, наконец, вызывается.

Пример кода:

 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, он будет превзойти любой другой возврат из обычного блока. То есть, следующий блок вернет false:

 try { return true; } finally { return false; } 

То же самое с бросанием исключений из блока finally.

Вот официальные слова из спецификации Java Language Specification.

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 фактически делает это явным:

JLS 14.17 Оператор возврата

 ReturnStatement: return Expression(opt) ; 

Оператор return без Expression пытается передать управление вызывающему методу или конструктору, который его содержит.

Оператор return с Expression пытается передать управление вызывающему методу, который содержит его; значение Expression становится значением вызова метода.

В предыдущих описаниях сказано « попытки передать управление », а не просто « управление передачей », потому что, если в методе или конструкторе есть какие-либо утверждения try чьи блоки try содержат оператор return , тогда любые finally предложения этих операторов try будут выполняться в порядок, самый внутренний до внешнего, до того, как управление передается вызывающему методу или конструктору. Резкое завершение предложения finally может привести к нарушению передачи управления, инициированного оператором return .

В дополнение к другим ответам важно указать, что «наконец» имеет право переопределить любое исключение / возвращаемое значение блоком 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(); } } 

Я попробовал приведенный выше пример с небольшими изменениями –

 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 finally блока оператор return будет выполнен снова. Но это не так. Он просто возвращает значение 2.

Вот выработка ответа Кевина . Важно знать, что выражение, которое будет возвращено, оценивается до, 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 не запускается по какой-либо другой причине).

Логичным способом думать об этом является:

  1. Код, помещенный в блок finally, должен быть выполнен независимо от того, что происходит в блоке try
  2. Поэтому, если код в блоке try пытается вернуть значение или выбросить исключение, элемент будет помещен «на полку» до тех пор, пока блок finally не сможет выполнить
  3. Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или бросать все, что ему нравится. В этом случае все, что осталось на полке, отбрасывается.
  4. Единственным исключением из этого является то, что VM полностью отключается во время блока try, например, «System.exit»

Кроме того, возrotation в итоге выкинет любое исключение. 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, поэтому будьте осторожны, проверяя все точки выхода при попытке в конце.

Наконец, это всегда работает, и это все, только потому, что оно появляется в коде после возвращения, не означает, что так оно и было реализовано. Среда выполнения 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() (или stream не сработает).

Вкратце, в официальной документации Java (нажмите здесь ) написано, что –

Если JVM завершает работу, пока выполняется код try или catch, блок finally может не выполняться. Аналогично, если stream, выполняющий код try или catch, прерывается или убивается, блок 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; } } 

Да, он будет вызван. В этом весь смысл наличия ключевого слова finally. Если выпрыгнуть из блока try / catch можно просто пропустить блок finally, это было бы то же самое, что и поставить System.out.println вне try / catch.

Да, это будет. Независимо от того, что происходит в вашем блоке try или catch, если иное не вызвано вызовом System.exit () или JVM. если в блоке (-ах) есть какой-либо оператор возврата, он, наконец, будет выполнен до этого оператора return.

Да, это будет. Только в случае, если это не произойдет, произойдет JVM или сбой

Да, блок finally всегда выполняется. Большинство разработчиков используют этот блок для закрытия соединения с базой данных, объекта результатов, объекта-оператора, а также использования в спящем режиме java для отката транзакции.

Ответ прост ДА .

ВХОД:

 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 

Это на самом деле верно на любом языке … наконец, всегда будет выполняться перед оператором return, независимо от того, где это возrotation находится в теле метода. Если бы это было не так, блок finally не имел бы большого значения.

Потому что окончательный всегда вызывается в любых случаях, которые у вас есть. У вас нет исключения, оно все еще называется, исключение catch, оно все еще называется

Рассмотрите это в обычном ходе выполнения (т. Е. Без какого-либо исключения): если метод не является «void», он всегда явно возвращает что-то, но, наконец, всегда выполняется

Если исключение выбрасывается, он, наконец, запускается. Если исключение не выбрасывается, оно, наконец, запускается. Если исключение поймано, он, наконец, запускается. Если исключение не поймано, он, наконец, запускается.

Только время, когда он не запускается, – это когда JVM завершает работу.

Наконец, блок всегда выполняет ли дескриптор исключений или нет. Если какое-либо исключение возникло до попытки блокировки, то, наконец, блок не будет выполняться.

Логичным способом думать об этом является:

Код, помещенный в блок 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 (), либо вызывая фатальную ошибку, из-за которой процесс прерывается: иногда он упоминается неформально как «горячая точка» или «Dr Watson» в Windows) предотвратит ваш окончательный блок выполнено!

Нет ничего, что помешало бы нам встраивать блоки try / catch / finally (например, класть блок try / finally внутри блока try / catch или наоборот), и это не такая необычная вещь.

Рассмотрим следующую программу:

 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; } } 

В дополнение к вопросу о возврате, наконец, заменяя возврат в блоке try, то же самое относится к исключению. Блок finally, который генерирует исключение, заменит возврат или исключение, вызванное из блока try.

Interesting Posts
Давайте будем гением компьютера.