在Java try{} ... catch{} ... finally{}
块中,finally{}
中的代码通常被认为是“保证”运行,无论try / catch中发生什么。但是,我知道至少有两种情况,不执行:
System.exit(0)
;或者,printStackTrace()
并退出)是否有任何其他程序行为会阻止finally{}
块中的代码执行?代码在什么具体条件下执行?
编辑:由于NullUserException指出,第二种情况实际上并非如此。我认为这是因为标准错误中的文本在标准输出之后打印出来,防止文本在没有向上滚动的情况下被看到。道歉。
答案 0 :(得分:33)
如果您致电System.exit()
,程序会立即退出而不会调用finally
。
JVM崩溃,例如分段错误,也会阻止最终被调用。即JVM此时立即停止并生成崩溃报告。
无限循环也会阻止最终被调用。
抛出Throwable时始终会调用finally块。即使你调用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()之后!
答案 1 :(得分:9)
try
块中的无限循环。
损坏内存?程序不再按书面运行?我实际上已经在DOS机器上调试了一次。
答案 2 :(得分:1)
当最终自身抛出异常(或导致错误)时,有可能部分执行
答案 3 :(得分:1)
一个可能是“最终是守护程序线程的一部分,它可能无法执行”。
答案 4 :(得分:1)
最终不会被召唤的唯一时间是:
如果电源关闭
答案 5 :(得分:1)
在try块中的不同语句中测试 finally 块。
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);
Runtime.getRuntime().exit(0);
Runtime.getRuntime().halt(0);
答案 6 :(得分:0)
我认为当JVM由于任何原因突然退出时,这可能是因为控件不会进入finally块而永远不会执行。
答案 7 :(得分:0)
您可以将其作为守护程序线程的一部分。您可以使用方法setDaemon(boolean status)
,该方法用于将当前线程标记为守护程序线程或用户线程,并在需要时退出JVM。这将使您能够在finally{}
执行之前退出JVM。
答案 8 :(得分:0)
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...
}
我知道你们没有人会这样做,所以我犹豫是否愿意将此作为一种可能的情况添加,但是,呃,这是星期五,这是什么意思; )