Каковы обстоятельства, при которых блок finally {} не будет выполняться?
в Java try{} ... catch{} ... finally{}
блок, код внутри finally{}
обычно считается "гарантированным" для запуска независимо от того, что происходит в try/catch. Однако, я знаю по крайней мере два обстоятельства, при которых он будет не выполнить:
- если
System.exit(0)
называется; или - если исключение брошено полностью до JVM и происходит поведение по умолчанию (т. е.
printStackTrace()
и выход)
есть ли какие-либо другие поведения программы, которые предотвратит код в finally{}
блок от выполнения? При каких конкретных условиях будет выполняться код или нет?
EDIT: как указал NullUserException, второй случай на самом деле не верен. Я думал, это потому, что текст в стандартной ошибке печатается после этого в standard out, предотвращая просмотр текста без прокрутки. :) Извинения.
9 ответов
если вы называете System.exit()
программа немедленно завершает работу без finally
называют.
сбой JVM, например, ошибка сегментации, также предотвратит окончательный вызов. т. е. JVM немедленно останавливается на этом этапе и создает отчет о сбое.
бесконечный цикл также предотвратит окончательный вызов.
блок finally всегда вызывается, когда выбрасывается Throwable. Даже если вы вызываете поток.stop (), который запускает ThreadDeath
быть брошенным в целевой поток. Это можно поймать (это Error
) и блок finally будет вызван.
public static void main(String[] args) {
testOutOfMemoryError();
testThreadInterrupted();
testThreadStop();
testStackOverflow();
}
private static void testThreadStop() {
try {
try {
final Thread thread = Thread.currentThread();
new Thread(new Runnable() {
@Override
public void run() {
thread.stop();
}
}).start();
while(true)
Thread.sleep(1000);
} finally {
System.out.print("finally called after ");
}
} catch (Throwable t) {
System.out.println(t);
}
}
private static void testThreadInterrupted() {
try {
try {
final Thread thread = Thread.currentThread();
new Thread(new Runnable() {
@Override
public void run() {
thread.interrupt();
}
}).start();
while(true)
Thread.sleep(1000);
} finally {
System.out.print("finally called after ");
}
} catch (Throwable t) {
System.out.println(t);
}
}
private static void testOutOfMemoryError() {
try {
try {
List<byte[]> bytes = new ArrayList<byte[]>();
while(true)
bytes.add(new byte[8*1024*1024]);
} finally {
System.out.print("finally called after ");
}
} catch (Throwable t) {
System.out.println(t);
}
}
private static void testStackOverflow() {
try {
try {
testStackOverflow0();
} finally {
System.out.print("finally called after ");
}
} catch (Throwable t) {
System.out.println(t);
}
}
private static void testStackOverflow0() {
testStackOverflow0();
}
печать
finally called after java.lang.OutOfMemoryError: Java heap space
finally called after java.lang.InterruptedException: sleep interrupted
finally called after java.lang.ThreadDeath
finally called after java.lang.StackOverflowError
Примечание: В каждом случае поток продолжал работать, даже после этого, OOME, Прерванный и поток.стоп!
бесконечный цикл в try
заблокировать.
поврежден оперативной памяти? Программа больше не работает так, как написано? Я действительно отладил это однажды на машине DOS.
существует вероятность частичного выполнения, когда, наконец, сам выдает исключение (или приводит к ошибке)
единственный раз, наконец, не будет называться:
Если питание отключается
- если вы вызываете систему.exit ()
- если JVM падает первым
- если есть бесконечный цикл в try блок
- если питание отключается
тестирование наконец-то блок в другом операторе в блоке try.
public static void main(String [] args){
try{
System.out.println("Before Statement");
/*** Statement ***/
System.out.println("After Statement");
}
catch(Exception e){
}
finally{
System.out.println("Finally is Executed");
}
заявления, в котором finally блок выполняется следующие:
Thread.currentThread().interrupted();
Thread.currentThread().destroy();
Thread.currentThread().stop();
Thread.sleep(10);
Thread.currentThread().interrupt();
Runtime.getRuntime().addShutdownHook(Thread.currentThread());
- если произошло какое-либо исключение.
- если нет исключение.
заявления, в котором блок finally не выполняется следующие:
Thread.currentThread().suspend();
System.exit(0);
- JVM-машине разбился.
- питание чипа CPU отключается.
- OS убивает процесс JVM.
Runtime.getRuntime().exit(0);
Runtime.getRuntime().halt(0);
Я думаю, что когда JVM внезапно выходит по какой-либо причине, это может быть причиной того, что элемент управления не войдет в блок finally и никогда не будет выполняться.
Вы можете сделать его частью потока демона. Вы можете использовать метод setDaemon(boolean status)
который используется для обозначения текущего потока как потока демона или пользовательского потока и выхода из JVM по мере необходимости. Это позволит вам выйти из JVM до finally{}
выполняется.
другой возможный экземпляр блока finally, который никогда не будет выполняться, будет связан с дизайном, в котором метод возвращается до ввода блока try, как в случае очень плохого кода, который я видел время от времени:
public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException {
if (checkSomeObjectState()) {
return new ObjectOfSomeType();
}
try {
// yada yada yada...
} catch (SomeHorrendousException shexc) {
// wow, do something about this horrendous exception...
} finally {
// do some really important cleanup and state invalidation stuff...
}
Я знаю, что никто из вас никогда бы этого не сделал, поэтому я колебался добавить это как возможный сценарий, но подумал, Эх, это пятница, какого черта;)