Каковы обстоятельства, при которых блок finally {} не будет выполняться?
В блоке Java try{} ... catch{} ... finally{}
код в finally{}
обычно считается "гарантированным" для запуска независимо от того, что происходит в try/catch. Однако я знаю, по крайней мере, о двух обстоятельствах, при которых он не будет выполняться:
- Если
System.exit(0)
вызывается; или,
- если исключение генерируется вплоть до JVM и происходит поведение по умолчанию (т.е.
printStackTrace()
и выход)
Есть ли другие программные поведения, которые предотвратят выполнение кода в блоке finally{}
? В каких конкретных условиях будет выполняться код или нет?
EDIT: Как указывало NullUserException, второй случай на самом деле не соответствует действительности. Я думал, это потому, что текст стандартной ошибки печатается после этого в стандартном формате, предотвращая просмотр текста без прокрутки.:) Извинения.
Ответы
Ответ 1
Если вы вызываете System.exit()
, программа немедленно выйдет без вызова finally
.
Сбой JVM, например. Ошибка сегментации также предотвратит окончательное вызванное. то есть JVM немедленно останавливается в этой точке и создает отчет о сбое.
Бесконечный цикл также предотвратит, наконец, вызов.
Блок finally всегда вызывается, когда бросается Throwable. Даже если вы вызываете Thread.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
Примечание: в каждом случае поток продолжал работать, даже после SO, OOME, Interrupted и Thread.stop()!
Ответ 2
Бесконечный цикл в блоке try
.
Коррумпированная оперативная память? Программа больше не работает так, как написано? Я действительно отлаживал это однажды на машине DOS.
Ответ 3
Есть вероятность частичного выполнения, когда, наконец, сам генерирует исключение (или приводит к ошибке)
Ответ 4
Можно было бы: "A, наконец, является частью потока daeomon, он не может быть выполнен".
Ответ 5
Единственными моментами, которые окончательно не будут вызываться, являются:
если питание отключается
- если вы вызываете System.exit()
- если сначала сбой JVM
- если в блоке try есть бесконечный цикл
- Если питание отключается
Ответ 6
Тестирование блока 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");
}
Заявления, в которых выполняется окончательный блок:
-
Thread.currentThread().interrupted();
-
Thread.currentThread().destroy();
-
Thread.currentThread().stop();
-
Thread.sleep(10);
-
Thread.currentThread().interrupt();
-
Runtime.getRuntime().addShutdownHook(Thread.currentThread());
- Если возникло исключение.
- Если нет исключения.
Заявления, в которых окончательный блок не выполняется:
-
Thread.currentThread().suspend();
-
System.exit(0);
- JVM разбился.
- Питание к чипу процессора отключается.
- ОС убивает процесс JVM.
-
Runtime.getRuntime().exit(0);
-
Runtime.getRuntime().halt(0);
Ответ 7
Я думаю, что когда JVM неожиданно выходит из-за какой-либо причины, это может быть причиной того, что элемент управления не войдет в блок finally и никогда не выполнится.
Ответ 8
Вы можете сделать его частью Daemon Thread. Вы можете использовать метод setDaemon(boolean status)
, который используется для отметки текущего потока как потока потока или пользовательского потока и выхода из JVM по мере необходимости. Это позволит вам выйти из JVM до выполнения finally{}
.
Ответ 9
Еще один возможный экземпляр блока 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...
}
Я знаю, что никто из вас никогда не сделает этого, поэтому я не решался добавить это как возможный сценарий, но подумал, а в пятницу, что за черт; )