考虑到这段代码,我能绝对确定finally块总是执行的吗,不管something()是什么?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
考虑到这段代码,我能绝对确定finally块总是执行的吗,不管something()是什么?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
当前回答
是的,写在这里
如果在执行try或catch代码时JVM退出,那么finally块可能不会执行。同样,如果执行try或catch代码的线程被中断或终止,那么即使整个应用程序继续运行,finally块也可能不会执行。
其他回答
这是Java语言规范中的官方词汇。
14.20.2.执行try finally和try catch finally
带有finally块的try语句通过首先执行try块来执行。然后有一个选择:如果try块的执行正常完成,[…]如果try块的执行因抛出值V而突然完成,[…]如果由于任何其他原因R,try块的执行突然完成,则执行finally块。然后有一个选择:如果finally块正常完成,则try语句由于原因R而突然完成。如果finally块因原因S而突然完成,则try语句因原因S突然完成(并且原因R被丢弃)。
返回的规范实际上明确了这一点:
JLS 14.17退货声明
退货声明:返回表达式(opt);没有表达式的return语句试图将控制传递给包含它的方法或构造函数的调用者。带有表达式的return语句试图将控制权传递给包含它的方法的调用者;表达式的值变为方法调用的值。前面的描述说的是“试图传递控制”而不仅仅是“传递控制”,因为如果在方法或构造函数中有任何try语句,其try块包含return语句,那么在将控制传递给方法或构造函数的调用程序之前,这些try语句的任何finally子句都将按从内到外的顺序执行。finally子句的突然完成可能会中断由return语句发起的控制权转移。
除其他响应外,重要的是要指出,“finally”有权通过try重写任何异常/返回值。。捕捉块。例如,以下代码返回12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
类似地,以下方法不会引发异常:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
虽然以下方法确实抛出了它:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
我试过了,它是单线程的。
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception ignored) {
} finally {
System.out.println("finally");
}
}
主线程将永远处于等待状态,因此最终不会被调用,
因此控制台输出不会在wait()或finally之后打印String:
同意@Stephen C的观点,上述示例是这里提到的第三个案例之一:
在以下代码中添加更多这样的无限循环可能性:
// import java.util.concurrent.Semaphore;
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception ignored) {
} finally {
System.out.println("finally");
}
}
案例2:如果JVM首先崩溃
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public static void main(String args[]) {
try {
unsafeMethod();
//Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
参考:如何使JVM崩溃?
情况6:如果finally块将由守护程序线程执行,并且所有其他非守护程序线程在finally被调用之前退出。
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
输出:这不会打印“finally”,这意味着“守护进程线程”中的“finally块”没有执行
主螺纹打印线程:线程[My Daemon线程,5,main]:状态:BLOCKED线程:线程[main,5,main]:状态:RUNNABLE线程:线程[Monitor Ctrl-Break,5,main]:状态:RUNNABLE主线程启动的线程计数:3------------------------------------------------- Daemon线程打印线程:线程[My Daemon线程,5,main]:状态:RUNNABLE线程:线程[Monitor Ctrl-Break,5,main]:状态:RUNNABLE主线程启动的线程计数:2------------------------------------------------- 进程已完成,退出代码为0
除了最后替换try块中的返回之外,异常也是如此。引发异常的finally块将替换try块中引发的返回或异常。
下面是凯文的回答。重要的是要知道,要返回的表达式在finally之前求值,即使在finally之后返回。
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
return 42;
}
}
输出:
X
finally trumps return... sort of
42