Всегда ли выполняется блок finally в Java?

Учитывая этот код, могу ли я быть абсолютно уверен, что 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");
}
15.09.2008 17:43:54
Если это не так, ключевое слово должно быть названо probablyвместо.
Noon Silk 13.05.2010 06:18:05
polygenelubricants 13.05.2010 06:33:07
Boann 23.09.2013 00:52:04
Эффективный Java говорит иначе. Informit.com/articles/article.aspx?p=1216151&seqNum=7
Binoy Babu 14.12.2014 03:08:59
@BinoyBabu, финализатор ! = finally; финализатор == finalize()метод.
jaco0646 12.07.2016 16:11:35
30 ОТВЕТОВ
РЕШЕНИЕ

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

Единственные времена finallyне будут называться:

  1. Если вы вызываете System.exit()
  2. Если вы вызываете Runtime.getRuntime().halt(exitStatus)
  3. Если JVM падает в первую очередь
  4. Если JVM достигает бесконечного цикла (или некоторого другого не прерываемого, не завершающего оператора) в блоке tryorcatch
  5. Если ОС принудительно завершает процесс JVM; например, kill -9 <pid>в UNIX
  6. Если хост-система умирает; например, сбой питания, аппаратная ошибка, паника ОС и т. д.
  7. Если finallyблок будет выполняться потоком демона и все другие потоки, не являющиеся демонами, завершатся до finallyвызова
2671
31.10.2019 21:47:57
На самом деле thread.stop()не обязательно препятствует выполнению finallyблока.
Piotr Findeisen 30.03.2011 21:12:19
Как насчет того , чтобы сказать , что finallyблок будет называться после того, как в tryблоке, и перед тем управление переходит к следующим заявлениям. Это согласуется с блоком try, включающим бесконечный цикл и, следовательно, блок finally, который фактически никогда не вызывается.
Andrzej Doyle 16.09.2011 11:24:48
есть и другой случай, когда мы используем вложенные блоки try-catch-finally
ruhungry 22.03.2014 20:39:34
Кроме того, блок finally не вызывается в случае исключения, генерируемого потоком демона.
Amrish Pandey 11.09.2014 12:07:46
@BinoyBabu - это о финализаторе, а не окончательном блоке
avmohan 5.01.2017 10:17:01

Наконец, всегда выполняется finally, если нет ненормального завершения программы (например, вызов System.exit (0) ..). Итак, ваш системник будет напечатан

21
19.01.2016 11:39:56

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

9
15.09.2008 17:46:40

Пример кода:

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
561
5.12.2017 17:20:06
К сведению: в C # поведение идентично, за исключением того, что замена оператора в finally-clause return 2;недопустима (Compiler-Error).
Alexander Pacha 31.10.2013 08:08:33
Вот важная деталь, о которой следует знать: stackoverflow.com/a/20363941/2684342
WoodenKitty 3.12.2013 23:37:57
Вы даже можете добавить инструкцию возврата в сам блок finally, который затем переопределит предыдущее возвращаемое значение. Это также волшебным образом отбрасывает необработанные исключения. На этом этапе вы должны рассмотреть возможность рефакторинга вашего кода.
Zyl 15.04.2015 17:25:33
Это на самом деле не доказывает, что, наконец, козыри возвращаются. Возвращаемое значение выводится из кода вызывающего абонента. Не похоже, чтобы доказать много.
Trimtab 21.06.2016 04:20:19
Извините, но это демонстрация, а не доказательство. Это только доказательство, если вы можете показать, что этот пример всегда ведет себя таким образом на всех платформах Java, И что подобные примеры также всегда ведут себя так.
Stephen C 20.08.2017 01:24:21

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

7
15.09.2008 18:03:05

Блок finally всегда выполняется, если не происходит аварийного завершения программы, вызванного сбоем JVM или вызовом System.exit(0).

Кроме того, любое значение, возвращаемое из блока finally, будет переопределять значение, возвращаемое до выполнения блока finally, поэтому будьте осторожны при проверке всех точек выхода при использовании try finally.

18
3.05.2017 21:53:37

Кроме того, хотя это плохая практика, если в блоке finally есть оператор return, он превзойдет любой другой возврат из обычного блока. То есть следующий блок вернул бы false:

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

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

391
15.09.2008 18:19:53
Это действительно плохая практика. См. Stackoverflow.com/questions/48088/… для получения дополнительной информации о том, почему это плохо.
John Meagher 16.09.2008 02:47:56
Согласовано. Возврат в finally {} игнорирует любое исключение, выданное в try {}. Страшно!
neu242 22.10.2008 07:12:20
@ dominicbri7 Почему вы думаете, что это лучшая практика? И почему это должно отличаться, когда функция / метод не имеет значения?
corsiKa 12.07.2011 20:26:36
По той же причине я НИКОГДА не использую goto в моих кодах C ++. Я думаю, что множественные возвраты затрудняют чтение и затрудняют отладку (конечно, в действительно простых случаях это не применимо). Я полагаю, что это всего лишь личное предпочтение, и в конце концов вы можете добиться того же результата, используя любой из этих методов
dominicbri7 13.07.2011 11:47:11
Я склонен использовать несколько возвратов, когда происходит какой-то исключительный случай. Например, если (есть причина не продолжать) вернуться;
iHearGeoff 22.02.2013 23:24:00

Также возврат в, наконец, отбросит любое исключение. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

19
15.09.2008 19:26:15

Логичный способ думать об этом:

  1. Код, помещенный в блок finally, должен выполняться независимо от того, что происходит в блоке try
  2. Таким образом, если код в блоке try пытается вернуть значение или сгенерировать исключение, элемент помещается «на полку», пока не будет выполнен блок finally.
  3. Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или выдавать все, что ему нравится. В этом случае все, что осталось «на полке», отбрасывается.
  4. Единственное исключение из этого, если виртуальная машина полностью отключается во время блока try, например, через «System.exit».
42
15.09.2008 19:26:44
Это просто «логичный способ думать об этом» или действительно, как блок finally должен работать в соответствии со спецификациями? Ссылка на ресурс Sun была бы очень интересна здесь.
matias 26.05.2010 19:27:32

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

7
1.10.2008 15:15:44

Я попробовал приведенный выше пример с небольшой модификацией

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выполняется выход.

После выполнения finallyблока tryблок возвращает 2, а не 12, потому что этот оператор возврата больше не выполняется.

Если вы будете отлаживать этот код в Eclipse , то вы получите ощущение , что после выполнения System.outиз finallyблока на returnзаявлении tryблока выполняются снова. Но это не так. Он просто возвращает значение 2.

120
8.02.2015 04:03:00
Этот пример потрясающий, он добавляет то, что не было упомянуто в десятках, наконец, связанных тем. Я думаю, что едва ли любой разработчик будет знать это.
HopefullyHelpful 8.09.2016 09:11:52
Что если бы iбыл не примитив, а объект Integer.
Yamcha 9.09.2016 20:50:22
Мне трудно понять этот случай. docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17 говорит, что «оператор return с выражением пытается передать управление вызывающему методу или лямбда-телу, содержащему это .... Если вычисление Выражения завершается нормально, производя значение V .. "Что я мог догадаться из этого утверждения - кажется, что return не вычисляет выражение снова, когда оно оценивает значение V, поэтому изменил не влияет на возвращаемое значение, поправьте меня.
meexplorer 15.11.2016 18:21:19
Но я не нашел никаких подтверждений этому, где упоминалось, что return не оценивает выражение снова.
meexplorer 15.11.2016 18:27:11
@meexplorer немного опоздал, но это объясняется в JLS 14.20.2. Выполнение try-finally и try-catch-finally - сформулировано немного сложнее, 14.17. Заявление о возврате также необходимо прочитать
user85421-Banned 17.05.2017 19:18:16

Наконец, всегда запускается, и в этом весь смысл, просто потому, что он появляется в коде после возврата, не означает, что так оно и реализовано. Среда выполнения Java отвечает за запуск этого кода при выходе из tryблока.

Например, если у вас есть следующее:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

Среда выполнения сгенерирует что-то вроде этого:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Если генерируется неперехваченное исключение, finallyблок будет запущен, и исключение продолжит распространяться.

13
13.05.2010 06:23:53

Потому что блок finally всегда будет вызываться до тех пор, пока вы не вызовете System.exit()(или не произойдет сбой потока).

10
13.05.2010 06:19:17

Вот и вся идея окончательного блока. Это позволяет вам убедиться, что вы делаете очистки, которые в противном случае могли бы быть пропущены, потому что вы возвращаетесь, среди прочего, конечно.

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

54
1.09.2015 17:11:29
Это очень слабый ответ. stackoverflow.com/a/65049/715269
Gangnus 7.05.2019 18:19:17

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

3
13.05.2010 06:19:47

В дополнение к другим ответам важно указать, что '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();
    }
}
161
28.10.2016 14:35:35
Следует отметить, что средний регистр является именно той причиной, по которой наличие оператора return внутри блока finally абсолютно ужасно (он может скрыть любой Throwable).
Dimitris Andreou 13.05.2010 11:54:06
Кто не хочет удивляться OutOfMemoryError? ;)
RecursiveExceptionException 7.02.2019 18:06:06
Я проверил это, и это подавляет такую ​​ошибку (yipes!). Он также генерирует предупреждение, когда я его компилирую (ууу!). И вы можете работать вокруг него, определяя переменную возвращения , а затем с помощью return retVal после того, как в finallyблоке, хотя это, конечно , предполагает , что вы подавляются некоторые другие исключения , потому что код не имеет смысла иначе.
Maarten Bodewes 22.12.2019 16:02:48

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

3
13.05.2010 11:50:14

Это потому, что вы присвоили значение i как 12, но не вернули значение i в функцию. Правильный код выглядит следующим образом:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
11
20.08.2015 07:00:09

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

14.20.2. Выполнение try-finally и try-catch-finally

tryЗаявление с finallyблоком выполняется первым выполнением tryблока. Тогда есть выбор:

  • Если выполнение tryблока завершается нормально, [...]
  • Если выполнение tryблока завершается внезапно из- throwза значения V , [...]
  • Если выполнение tryблока завершается внезапно по любой другой причине R , то 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оператором.

257
7.06.2016 19:51:36

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

Только когда он не запускается, происходит выход из JVM.

4
13.10.2011 16:01:55

Попробуйте этот код, вы поймете, что код в блоке finally выполняется после оператора return .

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;
    }
}
4
17.04.2012 09:06:56

Нет, не всегда одним случаем исключения является // 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");
        }
    }
}
18
20.08.2018 06:02:03
И это одна из причин, по которой вам никогда не следует вызывать System.exit () ...
Franz D. 10.09.2018 18:34:23

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

8
16.08.2013 12:00:20

Вот разработка ответа Кевина . Важно знать, что возвращаемое выражение вычисляется раньше 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
117
23.05.2017 12:34:53
Важно знать.
Aminadav Glickshtein 6.07.2018 12:06:59
Полезно знать и имеет смысл. Кажется, что возвращение значения return - это то, что происходит после finally. Вычисление возвращаемого значения ( printX()здесь) по-прежнему предшествует этому.
Albert 26.06.2019 10:58:06
хороший пример со всеми 3 «возвращающимися» точками!
radistao 3.01.2020 12:54:49

Да, это будет. Единственный случай, когда это не будет, JVM выходит или вылетает

8
14.01.2014 22:29:17

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

4
17.02.2014 08:48:25

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

Если JVM завершает работу во время выполнения кода try или catch, блок finally может не выполняться. Аналогично, если поток, выполняющий код try или catch, прерывается или уничтожается, блок finally может не выполняться, даже если приложение в целом продолжается.

10
13.10.2014 21:51:50

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

9
2.12.2014 12:30:14

finally выполнит и это точно.

finally не будет выполняться в следующих случаях:

Случай 1 :

Когда вы выполняете System.exit().

случай 2:

Когда ваша JVM / Thread падает.

случай 3:

Когда ваше выполнение остановлено между вручную.

7
11.11.2016 10:39:47

Я был очень смущен всеми ответами, предоставленными на разных форумах, и решил наконец написать код и посмотреть. Выход является:

Наконец, будет выполнен, даже если в блоке try и catch есть return.

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

Вывод

пытаться

Напиши мне, наконец,

  1. Если return заменяется на System.exit(0)блок try и catch в приведенном выше коде, и перед ним возникает исключение по любой причине.
5
13.05.2015 11:52:58