Учитывая этот код, могу ли я быть абсолютно уверен в том, что блок 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");
}
2622
jonny five 15 Сен 2008 в 21:43
675
В противном случае ключевое слово должно быть названо probably.
 – 
Noon Silk
13 Май 2010 в 10:18
3
В эффективной java указано иное informit.com/articles/article.aspx?p= 1216151 & seqNum = 7
 – 
Binoy Babu
14 Дек 2014 в 06:08
34
@BinoyBabu, финализатор ! = finally; finalizer == метод finalize().
 – 
jaco0646
12 Июл 2016 в 19:11
4
Верно, действительно, «не всегда». Но тогда вы можете никогда не использовать слова «гарантировано» или «всегда».
 – 
MC Emperor
19 Янв 2017 в 22:40

31 ответ

Лучший ответ

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

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

  1. Если вы вызовете System.exit()
  2. Если вы вызовете Runtime.getRuntime().halt(exitStatus)
  3. Если сначала произойдет сбой JVM
  4. Если JVM достигает бесконечного цикла (или какого-либо другого непрерываемого, не завершающего оператора) в блоке try или catch
  5. Если ОС принудительно завершает процесс JVM; например, kill -9 <pid> в UNIX
  6. Если хост-система умирает; например, сбой питания, аппаратная ошибка, паника ОС и т. д.
  7. Если блок finally будет выполняться потоком демона, а все другие потоки, не являющиеся демонами, завершаются до вызова finally
2940
Ali Dehghani 1 Ноя 2019 в 00:47
47
На самом деле thread.stop() не обязательно предотвращает выполнение блока finally.
 – 
Piotr Findeisen
31 Мар 2011 в 01:12
207
Как насчет того, чтобы сказать, что блок finally будет вызываться после блока try, и до управление перейдет к следующим операторам. Это согласуется с блоком try, включающим бесконечный цикл, и, следовательно, блок finally никогда не вызывается.
 – 
Andrzej Doyle
16 Сен 2011 в 15:24
9
Есть и другой случай, когда мы используем вложенные блоки try-catch-finally
 – 
ruhungry
23 Мар 2014 в 00:39
7
Кроме того, блок finally не вызывается в случае исключения, созданного потоком демона.
 – 
Amrish Pandey
11 Сен 2014 в 16:07
15
- Это про финализатор, а не окончательный блок
 – 
avmohan
5 Янв 2017 в 13:17

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

  1. Код, помещенный в блок finally, должен выполняться независимо от того, что происходит в блоке try.
  2. Поэтому, если код в блоке try пытается вернуть значение или вызвать исключение, элемент помещается `` на полку '' до тех пор, пока блок finally не сможет выполнить
  3. Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или отбрасывать все, что угодно. В этом случае все, что осталось «на полке», выбрасывается.
  4. Единственное исключение из этого - если виртуальная машина полностью выключается во время блока попытки, например. от 'System.exit'
42
Garth Gilmour 15 Сен 2008 в 23:26
10
Это просто «логический способ думать об этом» или действительно так, как предполагается, что блок finally должен работать в соответствии со спецификациями? Здесь была бы очень интересна ссылка на ресурс Sun.
 – 
matias
26 Май 2010 в 23:27

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

21
shyam 19 Янв 2016 в 14:39

Нет, не всегда одним исключением является // 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");
        }
    }
}
19
Ram 20 Авг 2018 в 09:02
И это одна из причин, по которой вам действительно никогда не следует вызывать System.exit () ...
 – 
Franz D.
10 Сен 2018 в 21:34

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

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

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

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

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

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

12
Motti 13 Май 2010 в 10:23

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

10
Mendelt 15 Сен 2008 в 21:46

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

10
Jay Riggs 13 Май 2010 в 10:19

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

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.
    }
}
8
sam 30 Мар 2020 в 22:42
Разве это не должно быть наконец-то sb.setLength(0)?
 – 
user7294900
5 Сен 2018 в 09:38
Sb.setLength (0) просто очистит данные в StringBuffer. Итак, sb = null отсоединит объект от ссылки.
 – 
sam
5 Сен 2018 в 20:16
Разве «xyz» не следует печатать дважды на выходе? Поскольку функция вызывалась дважды, почему «finally» было только один раз?
 – 
fresko
13 Фев 2019 в 13:22
3
Это не очень хорошая практика. Этот блок finally с sb = null; просто добавляет ненужный код. Я понимаю, что вы имеете в виду, что блок finally - хорошее место для освобождения ресурсов, таких как соединение с базой данных или что-то в этом роде, но имейте в виду, что ваш пример может сбить с толку новичков.
 – 
Roc Boronat
16 Фев 2019 в 02:58
1
Спасибо, я добавил строки System.out.println("---AGAIN2---"); System.out.println(sb);, и теперь это более понятно. Как бы то ни было, вывод противоречил вашему тезису: p Я также добавил к вашему ответу, но редактирование должно быть принято модератором или кем-то в этом роде. В противном случае вы можете добавить их
 – 
fresko
19 Фев 2019 в 16:08

Блок finally выполняется всегда и перед возвратом (вычисленного) значения x.

System.out.println("x value from foo() = " + foo());

...

int foo() {
  int x = 2;
  try {
    return x++;
  } finally {
    System.out.println("x value in finally = " + x);
  }
}

Выход:

значение x в finally = 3
значение x из foo () = 2

10
srk 23 Июн 2021 в 21:30
Хороший наглядный пример, +1.
 – 
President James K. Polk
4 Фев 2020 в 22:37

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

7
Alex Miller 1 Окт 2008 в 19:15

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

finally будет выполнено, даже если в блоке try and 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");
}

Вывод

пытаться

Напечатайте меня НАКОНЕЦ

  1. Если return заменяется на System.exit(0) в блоке try and catch в приведенном выше коде и перед ним возникает исключение по любой причине.
7
Community 20 Июн 2020 в 12:12

Пример кода:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("something is printed");
    }
}

Выход:

something is printed. 
0
615
fareed 6 Окт 2021 в 01:10
20
К вашему сведению: в C # поведение идентично, за исключением того факта, что замена оператора в предложении finally на return 2; не допускается (ошибка компилятора).
 – 
Alexander Pacha
31 Окт 2013 в 12:08
15
Обратите внимание на важную деталь: stackoverflow.com/a/20363941/2684342
 – 
WoodenKitty
4 Дек 2013 в 03:37
22
Вы даже можете добавить оператор return в сам блок finally, который затем переопределит предыдущее возвращаемое значение. Это также волшебным образом отбрасывает необработанные исключения. На этом этапе вам следует подумать о рефакторинге вашего кода.
 – 
Zyl
15 Апр 2015 в 20:25
10
Это еще не доказывает, что козыри в конечном итоге возвращаются. Возвращаемое значение печатается из кода вызывающего абонента. Кажется, мало что доказывает.
 – 
Trimtab
21 Июн 2016 в 07:20
23
Извините, но это демонстрация, а не доказательство. Это только доказательство, если вы можете показать, что этот пример всегда ведет себя таким образом на всех платформах Java, И что аналогичные примеры также всегда ведут себя таким же образом.
 – 
Stephen C
20 Авг 2017 в 04:24

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

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

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

415
MooBob42 15 Сен 2008 в 22:19
102
Это ДЕЙСТВИТЕЛЬНО плохая практика. См. stackoverflow.com/questions/ 48088 /…, чтобы узнать, почему это плохо.
 – 
John Meagher
16 Сен 2008 в 06:47
23
Согласовано. Возврат в finally {} игнорирует любое исключение, созданное в try {}. Страшный!
 – 
neu242
22 Окт 2008 в 11:12
10
Как вы думаете, почему это лучше? И почему должно быть иначе, если функция / метод недействительны?
 – 
corsiKa
13 Июл 2011 в 00:26
8
По той же причине я НИКОГДА не использую goto в своих кодах на C ++. Я думаю, что множественные возвраты затрудняют чтение и отладку (конечно, в очень простых случаях это не применимо). Я думаю, это просто личное предпочтение, и, в конце концов, вы можете добиться того же, используя любой из методов.
 – 
dominicbri7
13 Июл 2011 в 15:47
18
Я обычно использую несколько возвратов в исключительных случаях. Например, если (есть причина не продолжать) return;
 – 
iHearGeoff
23 Фев 2013 в 03:24

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

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.

262
Kenster 7 Июн 2016 в 22:51

В дополнение к другим ответам важно указать, что '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();
    }
}
173
MC Emperor 28 Окт 2016 в 17:35
69
Следует отметить, что средний случай - это именно та причина, по которой наличие оператора return внутри блока finally абсолютно ужасно (оно может скрыть любой Throwable).
 – 
Dimitris Andreou
13 Май 2010 в 15:54
2
Кому не нужен подавленный OutOfMemoryError? ;)
 – 
RecursiveExceptionException
7 Фев 2019 в 21:06
Я протестировал его, и он подавляет такую ​​ошибку (ура!). Он также генерирует предупреждение, когда я его компилирую (ура!). И вы можете обойти это, определив возвращаемую переменную, а затем используя return retVal после блока finally, хотя это, конечно, предполагает, что вы подавили некоторые другие исключения, потому что код иначе не имеет смысла.
 – 
Maarten Bodewes
22 Дек 2019 в 19:02

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

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.

129
Jared Rummler 8 Фев 2015 в 07:03
12
Этот пример потрясающий, он добавляет то, что не упоминалось в десятках, наконец, связанных тем. Думаю, вряд ли кто-нибудь из разработчиков об этом узнает.
 – 
HopefullyHelpful
8 Сен 2016 в 12:11
5
Что, если бы i был не примитивом, а целочисленным объектом.
 – 
Yamcha
9 Сен 2016 в 23:50
Мне трудно понять этот случай. docs.oracle.com/javase/ specs / jls / se8 / html / jls-14.html # jls-14.17 говорит, что: «Оператор return с выражением пытается передать управление вызывающей стороне метода или тела лямбда, которое его содержит ... . Если вычисление Выражения завершается нормально, получая значение V .. "Что я мог догадаться из этого утверждения, так это то, что return не оценивает выражение снова после того, как оно оценивает значение V, поэтому изменение i не влияет на возвращаемое значение, поправьте меня.
 – 
meexplorer
15 Ноя 2016 в 21:21
Но я не смог найти никаких доказательств по этому поводу, где упоминается, что return не оценивает выражение снова.
 – 
meexplorer
15 Ноя 2016 в 21:27
1
Немного поздно, но это объясняется в JLS 14.20.2. Выполнение try-finally и try-catch-finally - сформулировано немного сложно, 14.17. Также необходимо прочитать Заявление о возврате
 – 
user85421
17 Май 2017 в 22:18

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

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

52
Chris Cooper 1 Сен 2015 в 20:11
Это очень слабый ответ. stackoverflow.com/a/65049/715269
 – 
Gangnus
7 Май 2019 в 21:19

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

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
10
Ankush soni 20 Авг 2015 в 10:00

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

ВВОД:

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
10
Meet Vora 8 Ноя 2017 в 11:48
2
Ответ прост: НЕТ.
 – 
Christophe Roussy
14 Дек 2017 в 11:25
1
Как? Объясните пожалуйста?
 – 
Meet Vora
14 Дек 2017 в 12:24
1
Прочтите принятый ответ, исходный вопрос о том, «Всегда ли он будет выполняться», и так будет не всегда. В вашем случае это будет, но это не ответ на исходный вопрос и может даже ввести в заблуждение новичков.
 – 
Christophe Roussy
14 Дек 2017 в 12:58
Тогда в каком случае он не будет выполнен?
 – 
Meet Vora
15 Дек 2017 в 13:41
Во всех случаях, упомянутых в других ответах, см. Принятый ответ с 1000+ голосами.
 – 
Christophe Roussy
18 Дек 2017 в 12:37

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

8
Gautam Viradiya 2 Дек 2014 в 15:30

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

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

10
bikz05 14 Окт 2014 в 01:51

НЕ ВСЕГДА

Спецификация языка 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 не гарантирует, что FIN выполняется после CODE . JLS гарантирует, что если выполняются CODE и NEXT , то FIN всегда будет выполняться после CODE и до ДАЛЕЕ .

Почему JLS не гарантирует, что блок finally всегда выполняется после блока try? Потому что это невозможно. Маловероятно, но возможно, что JVM будет прервана (уничтожение, сбой, отключение питания) сразу после завершения блока try, но до выполнения finally блокировать. JLS ничего не может сделать, чтобы этого избежать.

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

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

10
Anonymous Coward 7 Мар 2020 в 20:11
Приношу свои извинения за комментарий к такому старому ответу, но я не думаю, что сказать any software which for their proper behaviour depends on finally blocks always being executed after their try blocks complete are bugged. правильно. Блоки finally обычно используются для очистки ресурсов, чтобы предотвратить утечки. Как еще вы это сделали бы? Точно так же вы не можете (или не должны ...) ловить Error s, поскольку (обычно) нет разумного способа для нормального приложения их обработать.
 – 
filpa
9 Июн 2021 в 12:35
Если очистка в блоке finally связана с закрытием открытого файла, то невыполнение блока finally не является проблемой, ОС закрывает его при завершении программы. Если очистка - это удаление файла, который является проблемой, ОС не будет этого делать, когда программа будет прервана до того, как окончательно. Если другая часть системы зависит от java-программы, всегда выполняющей такое удаление, то система в целом и java-программа в частности ошибаются. Вы не можете рассчитывать на то, что, наконец, всегда выполняете. Вы можете положиться только на гарантию, которая, наконец, уже была выполнена, если NEXT был выполнен
 – 
Anonymous Coward
21 Июн 2021 в 11:48
Интересный вариант, хотя, насколько я могу судить, он заставляет некоторые части вашего дизайна. Чтобы расширить ваш пример удаления: будет ли у вас запущена задача «жнеца», которая отвечает за удаление (очистку) файлов? Я допускаю, что, учитывая ваше объяснение, использование finally может (при наличии достаточного количества времени, вероятно, будет ) вызвать ошибки, но дополнительное время на разработку (и тестирование) стоит потенциально незаметного улучшения стабильности. ? В более общем плане: зависит ли количество внимания, которое должно быть уделено конкретному проекту, от рассматриваемой подсистемы? В конце концов, время - ценный ресурс. :)
 – 
filpa
21 Июн 2021 в 15:01
1
Нет ничего плохого в том, чтобы использовать finally. Вам просто нужно знать, что он делает, а что нет. В конкретном случае удаления файла я бы сделал это в блоке finally. Но зная, что это не дает никаких гарантий (даже если последняя строка блока try завершена), я бы принял меры предосторожности, чтобы справиться с такой ситуацией. Таким образом, удаление предыдущих оставшихся файлов в качестве первого шага выполнения программы, если это программа служебного стиля, которая будет автоматически запускаться повторно. Если сбой системы в такой ситуации не вызывает беспокойства, тогда, конечно, не беспокойтесь
 – 
Anonymous Coward
22 Июн 2021 в 22:44

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

9
Karthikeyan 16 Авг 2013 в 16:00

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

8
abhig 15 Янв 2014 в 02:29

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

7
Scott Dorman 15 Сен 2008 в 22:03

Добавление к ответу @ 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 
8
Neuron 17 Апр 2018 в 18:35
Начиная с Java 1.8.162, это не результат.
 – 
sam
30 Апр 2018 в 11:28

Я пробовал это, он однопоточный.

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

main Thread всегда будет в состоянии wait, поэтому finally никогда не будет вызываться ,

Поэтому консольный вывод не будет print String: после 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
8
lue 7 Мар 2020 в 16:14
4
См. Принятый ответ. Это просто крайний случай «бесконечного цикла».
 – 
Stephen C
20 Авг 2017 в 04:27

finally будет выполняться, и это точно.

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

Случай 1 :

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

Случай 2:

Когда ваша JVM / Thread выходит из строя.

Случай 3:

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

8
L Joey 11 Ноя 2016 в 13:39

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

18
James A. N. Stauffer 15 Сен 2008 в 23:26

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

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

18
Youcef Laidani 4 Май 2017 в 00:53

Вот уточнение ответа Кевина. Важно знать, что возвращаемое выражение оценивается до 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
128
Community 23 Май 2017 в 15:34
8
Важно знать.
 – 
Aminadav Glickshtein
6 Июл 2018 в 15:06
Полезно знать, и это тоже имеет смысл. Кажется, что на самом деле возвращаемое значение return - это то, что следует после finally. Вычисление возвращаемого значения (здесь printX()) все еще предшествует этому.
 – 
Albert
26 Июн 2019 в 13:58
2
Неа. Приведенный выше код должен заменить System.out.println("finally trumps return... sort of"); на System.out.print("finally trumps return in try"); return 42;
 – 
Pacerier
10 Май 2020 в 04:21
Этот ответ совершенно очевиден, IMO, потому что return не возвращает какое-то волшебное продолжение, которое оценивается только в том случае, если вызывающий абонент печатает его или что-то еще. printX() вызывается до того, как произойдет return, независимо от try/catch или чего-либо еще.
 – 
Christopher Schultz
10 Июн 2022 в 00:39