Примечание. Если JVM завершает работу во время выполнения кода try или catch, то блок finally может не выполняться. Аналогично, если поток, выполняющий код try или catch, прерывается или завершается, блок finally может не выполняться, даже если приложение в целом продолжает работу.
Я не знаю других причин, по которым блок finally не выполнялся бы ...
@dhiller - Я почти уверен, что "отключение питания" включено в "Если JVM завершает работу ..." :-p
Джейсон Коко
2
@ Джейсон Коко: Прекращение (как при потере питания) - это не совсем то же самое, что выход; последнее представляет собой более или менее организованный процесс, завершающийся первым. ; p
user359996
2
AFAIK, если поток прерывается, он не останавливается немедленно. Код в потоке должен обнаружить прерывание и остановить его задачу, поэтому, наконец, код должен выполняться.
Bart van Heukelom
2
Я предполагаю, что если в блоке finally возникает исключение, остальная часть блока не выполняется.
Завершает работу текущей виртуальной машины Java. Аргумент служит кодом состояния; по соглашению ненулевой код состояния указывает на ненормальное завершение.
Этот метод вызывает exitметод в классе Runtime. Этот метод никогда не возвращает нормально.
Также исключение должно выключить виртуальную машину Java.
kaissun
3
Если при выполнении System.exit (0) возникает исключение, то блок finally будет выполняться.
Халил
50
Просто чтобы расширить то, что сказали другие, все, что не вызывает чего-то вроде выхода из JVM, повлечет за собой блок finally. Итак, следующий метод:
это действительно сбило меня с толку на пару часов несколько недель назад.
nickf
3
Считается плохой идеей возвращать значение из блока finally. Либо возврат только из блока try, либо возврат извне блока try / finally. Большинство IDE помечают это предупреждением.
Ран Бирон
1
@nickf Я так понимаю, вы больше не запутались. Не могли бы вы подробнее объяснить, почему возвращается 1, а не 0. Я мог только догадываться, что память (или это регистр), в которой хранится возвращаемое значение функции, которая изначально содержит 0, перезаписывается при выполнении блока finally. .
Yaneeve
2
Что любопытно, в C # нельзя возвращаться из блока finally.
JMCF125,
3
@RanBiron Конечно. На самом деле он не рекомендовал возвращаться внутрь блока finally, он только пытался продемонстрировать, что даже оператор return все равно вызовет выполнение кода в указанном блоке.
Aquarelle
15
В отношении System.exit также существуют определенные типы катастрофических сбоев, при которых блок finally может не выполняться. Если JVM полностью исчерпает память, она может просто выйти без перехвата или, наконец, не произойдет.
В частности, я помню проект, в котором мы по глупости пытались использовать
catch(OutOfMemoryError oome){// do stuff}
Это не сработало, потому что у JVM не осталось памяти для выполнения блока catch.
Когда выбрасывается OutOfMemoryError, обычно остается много памяти (чтобы остановить сбор мусора). Однако, если вы поймаете это неоднократно, вы, очевидно, вернетесь к обработке GC.
Том Хотин - tackline
Я подумал, что нельзя ловить непроверенные исключения!
Сергей Шевчик 01
1
Я попробовал на своей стороне, используя jdk7, но он обнаружил ошибку OutOfMemory!
Jaskey
10
try{for(;;);}finally{System.err.println("?");}
В этом случае finally не будет выполняться (если не Thread.stopвызывается устаревший или эквивалентный, скажем, через интерфейс инструментов).
Я не думаю, что есть загвоздка. Возможно, вы представляете себе уловку, которой нет. Если мы введем явный throw, то finallyблок будет выполняться, как ожидалось. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Tom Hawtin - tackline
9
Учебник Sun был неправильно процитирован здесь в этой ветке.
Примечание. Если JVM завершается во время выполнения кода try или catch, то блок finally не будет выполняться. Аналогично, если поток, выполняющий код try или catch, прерывается или завершается, блок finally не будет выполняться, даже если приложение в целом продолжает работу.
Если вы внимательно посмотрите на руководство Sun для блока finally, в нем не говорится «не будет выполняться», но «может не выполняться». Вот правильное описание
Примечание. Если JVM завершает работу во время выполнения кода try или catch, то блок finally может не выполняться. Аналогично, если поток, выполняющий код try или catch, прерывается или завершается, блок finally может не выполняться, даже если приложение в целом продолжает работу.
Очевидная причина такого поведения заключается в том, что вызов system.exit () обрабатывается в системном потоке времени выполнения, что может занять время для завершения работы jvm, в то время как планировщик потоков может наконец запросить выполнение. Итак, finally разработан так, чтобы всегда выполняться, но если вы закрываете jvm, может случиться так, что jvm отключится до того, как, наконец, будет запущен.
Технически блок try никогда не завершается, поэтому блок finally никогда не должен иметь шанса на выполнение. То же самое можно сказать и о бесконечном цикле.
Джефф Меркадо,
6
Если JVM завершается во время выполнения кода try или catch, то блок finally может не выполняться. ( источник )
Нормальное завершение работы - это происходит либо при выходе из последнего потока, не являющегося демоном, ИЛИ при Runtime.exit () ( источник )
Когда поток завершается, JVM выполняет инвентаризацию запущенных потоков, и если единственные оставшиеся потоки являются потоками демона, она инициирует упорядоченное завершение работы. Когда JVM останавливается, все оставшиеся потоки демона прекращаются, в конце концов блоки не выполняются, стеки не разматываются, JVM просто завершается. Демонические потоки следует использовать с осторожностью, от некоторых операций обработки можно безопасно отказаться в любое время без очистки. В частности, опасно использовать потоки демонов для задач, которые могут выполнять какой-либо ввод-вывод. Потоки демонов лучше всего сохранять для «служебных» задач, таких как фоновый поток, который периодически удаляет просроченные записи из кеша в памяти. ( источник )
Пример выхода последнего недемонического потока:
publicclassTestDaemon{privatestaticRunnable runnable =newRunnable(){@Overridepublicvoid 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.");}}};publicstaticvoid main(String[] args)throwsInterruptedException{Thread daemon =newThread(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:
1. Используйте System.exit ();
2. Если каким-то образом контроль выполнения не дойдет до блока try.
Видеть:
publicclassMain{publicstaticvoid main (String[]args){if(true){System.out.println("will exceute");}else{try{System.out.println("result = "+5/0);}catch(ArithmeticException e){System.out.println("will not exceute");}finally{System.out.println("will not exceute");}}}}
Я столкнулся с очень конкретным случаем, когда блок finally не выполняется, связанный конкретно с игровой платформой.
Я был удивлен, обнаружив, что блок finally в этом коде действия контроллера вызывается только после исключения, но никогда, когда вызов действительно удался.
try{InputStream is = getInputStreamMethod();
renderBinary(is,"out.zip");catch(Exception e){
e.printStackTrace();}finally{
cleanUp();}
Возможно, поток завершается или что-то еще, когда вызывается renderBinary (). Я подозреваю, что то же самое происходит и с другими вызовами render (), но я этого не проверял.
Я решил проблему, переместив renderBinary () после try / catch. Дальнейшее расследование показало, что play предоставляет аннотацию @Finally для создания метода, который запускается после выполнения действия контроллера. Предостережение здесь в том, что это будет вызываться после выполнения ЛЮБОГО действия в контроллере, поэтому это не всегда может быть хорошим выбором.
//If ArithmeticException Occur Inner finally would not be executedclassTemp{publicstaticvoid main(String[] s){try{int x =10/s.length;System.out.println(x);try{int z[]=newint[s.length];
z[10]=1000;}catch(ArrayIndexOutOfBoundsException e){System.out.println(e);}finally{System.out.println("Inner finally");}}catch(ArithmeticException e){System.out.println(e);}finally{System.out.println("Outer Finally");}System.out.println("Remaining Code");}}
Ответы:
из учебников Sun
Я не знаю других причин, по которым блок finally не выполнялся бы ...
источник
System.exit завершает работу виртуальной машины.
"Пока" не выводится в приведенном выше коде.
источник
Просто чтобы расширить то, что сказали другие, все, что не вызывает чего-то вроде выхода из JVM, повлечет за собой блок finally. Итак, следующий метод:
как ни странно, скомпилирует и вернет 1.
источник
В отношении System.exit также существуют определенные типы катастрофических сбоев, при которых блок finally может не выполняться. Если JVM полностью исчерпает память, она может просто выйти без перехвата или, наконец, не произойдет.
В частности, я помню проект, в котором мы по глупости пытались использовать
Это не сработало, потому что у JVM не осталось памяти для выполнения блока catch.
источник
В этом случае finally не будет выполняться (если не
Thread.stop
вызывается устаревший или эквивалентный, скажем, через интерфейс инструментов).источник
throw
, тоfinally
блок будет выполняться, как ожидалось.try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Учебник Sun был неправильно процитирован здесь в этой ветке.
Примечание. Если JVM завершается во время выполнения кода try или catch, то блок finally не будет выполняться. Аналогично, если поток, выполняющий код try или catch, прерывается или завершается, блок finally не будет выполняться, даже если приложение в целом продолжает работу.
Если вы внимательно посмотрите на руководство Sun для блока finally, в нем не говорится «не будет выполняться», но «может не выполняться». Вот правильное описание
Очевидная причина такого поведения заключается в том, что вызов system.exit () обрабатывается в системном потоке времени выполнения, что может занять время для завершения работы jvm, в то время как планировщик потоков может наконец запросить выполнение. Итак, finally разработан так, чтобы всегда выполняться, но если вы закрываете jvm, может случиться так, что jvm отключится до того, как, наконец, будет запущен.
источник
Также, если внутри
try
блока происходит взаимоблокировка / лайвлок .Вот код, который это демонстрирует:
Этот код дает следующий результат:
и "наконец" никогда не печатается
источник
Если JVM завершается во время выполнения кода try или catch, то блок finally может не выполняться. ( источник )
Нормальное завершение работы - это происходит либо при выходе из последнего потока, не являющегося демоном, ИЛИ при Runtime.exit () ( источник )
Когда поток завершается, JVM выполняет инвентаризацию запущенных потоков, и если единственные оставшиеся потоки являются потоками демона, она инициирует упорядоченное завершение работы. Когда JVM останавливается, все оставшиеся потоки демона прекращаются, в конце концов блоки не выполняются, стеки не разматываются, JVM просто завершается. Демонические потоки следует использовать с осторожностью, от некоторых операций обработки можно безопасно отказаться в любое время без очистки. В частности, опасно использовать потоки демонов для задач, которые могут выполнять какой-либо ввод-вывод. Потоки демонов лучше всего сохранять для «служебных» задач, таких как фоновый поток, который периодически удаляет просроченные записи из кеша в памяти. ( источник )
Пример выхода последнего недемонического потока:
Вывод:
источник
В следующих случаях блок finally не будет выполнен: -
System.exit(0)
вызывается изtry
блока.try
блокеТакже могут быть другие дополнительные случаи, когда блок finally не будет выполнен.
источник
Есть два способа остановить выполнение кода блока finally:
1. Используйте System.exit ();
2. Если каким-то образом контроль выполнения не дойдет до блока try.
Видеть:
источник
Я столкнулся с очень конкретным случаем, когда блок finally не выполняется, связанный конкретно с игровой платформой.
Я был удивлен, обнаружив, что блок finally в этом коде действия контроллера вызывается только после исключения, но никогда, когда вызов действительно удался.
Возможно, поток завершается или что-то еще, когда вызывается renderBinary (). Я подозреваю, что то же самое происходит и с другими вызовами render (), но я этого не проверял.
Я решил проблему, переместив renderBinary () после try / catch. Дальнейшее расследование показало, что play предоставляет аннотацию @Finally для создания метода, который запускается после выполнения действия контроллера. Предостережение здесь в том, что это будет вызываться после выполнения ЛЮБОГО действия в контроллере, поэтому это не всегда может быть хорошим выбором.
источник
источник