При каких обстоятельствах блок finally {} НЕ будет выполнен?
На Яве try{} ... catch{} ... finally{}
блок, код внутри finally{}
обычно считается "гарантированным", чтобы работать независимо от того, что происходит в try/catch. Однако я знаю как минимум два обстоятельства, при которых он не будет выполняться:
- Если
System.exit(0)
называется; или же, - если исключение выдается полностью до JVM, и происходит поведение по умолчанию (т.е.
printStackTrace()
и выход)
Существуют ли какие-либо другие программные поведения, которые будут препятствовать коду в finally{}
заблокировать от выполнения? При каких конкретных условиях будет выполняться код или нет?
РЕДАКТИРОВАТЬ: Как указывает NullUserException, второй случай на самом деле не соответствует действительности. Я думал, что это потому, что текст в стандартной ошибке печатается после этого в стандартном выводе, предотвращая просмотр текста без прокрутки вверх.:) Извиняюсь.
9 ответов
Если вы позвоните System.exit()
программа выходит сразу без finally
будучи призванным
Сбой JVM, например, ошибка сегментации, также будет препятствовать окончательному вызову. то есть JVM немедленно останавливается на этом этапе и выдает отчет о сбое.
Бесконечный цикл также предотвратит окончательный вызов.
Блок finally всегда вызывается, когда выбрасывается Throwable. Даже если вы вызываете Thread.stop(), который вызывает ThreadDeath
быть брошенным в целевой поток. Это можно поймать (это Error
) и блок finally будет вызван.
public static void main(String[] args) {
testOutOfMemoryError();
testThreadInterrupted();
testThreadStop();
testStackru();
}
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 testStackru() {
try {
try {
testStackru0();
} finally {
System.out.print("finally called after ");
}
} catch (Throwable t) {
System.out.println(t);
}
}
private static void testStackru0() {
testStackru0();
}
печать
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.StackruError
Примечание: в каждом случае поток продолжал работать, даже после SO, OOME, Interrupted и Thread.stop()!
Бесконечный цикл в try
блок.
Поврежденная RAM? Программа больше не работает как написано? Я на самом деле отладил это однажды на машине DOS.
Тестирование блока finally в другом операторе в блоке 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 разбился.
- Питание чипа процессора отключается.
- ОС убивает процесс JVM.
Runtime.getRuntime().exit(0);
Runtime.getRuntime().halt(0);
Можно было бы сказать: "Наконец, это часть потока daeomon, который не может быть выполнен".
Существует вероятность частичного выполнения, когда, наконец, само выдает исключение (или приводит к ошибке)
Единственные разы, когда окончательно не будут названы:
если питание отключается
- если вы вызываете System.exit()
- если JVM падает в первую очередь
- если есть бесконечный цикл в блоке try
- если питание отключается
Другой возможный экземпляр блока 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...
}
Я знаю, что никто из вас никогда этого не сделает, поэтому я не решался добавить это в качестве возможного сценария, но подумал: а, ну что, пятница, какого черта;)
Я думаю, что когда JVM неожиданно завершает работу по какой-либо причине, это может быть причиной того, что элемент управления не войдет в блок finally и никогда не выполнится.
Вы можете сделать его частью Daemon Thread. Вы можете использовать метод setDaemon(boolean status)
который используется для пометки текущего потока как потока демона или пользовательского потока и выхода из JVM по мере необходимости. Это позволит вам выйти из JVM до finally{}
выполнен.