Java中的finally块是否总是会被执行?

2684
考虑到这段代码,我能否绝对确定无论 something() 是什么,finally 语句块总是会被执行?
try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}

61
不总是。 - Boann
3
《Effective Java》认为情况并非如此。http://www.informit.com/articles/article.aspx?p=1216151&seqNum=7 - Binoy Babu
36
@BinoyBabu,_finalizer_不等于finally;_finalizer_指的是finalize()方法。 - jaco0646
4
没错,“不总是”是正确的。但是这样你就永远不能使用“保证”或“总是”这些词了。 - MC Emperor
2
@Boann 我会这样表达:在跳出 try-finally 结构之前,执行流程总是会经过 finally。如果它在其中失败了,我也没关系,因为 finally 的主要目的是确保其他代码部分不会出现混乱。 - Imperishable Night
显示剩余3条评论
52个回答

7
除了finally中的return可以替换try块中的return之外,对于异常也是如此。在finally块中抛出的异常将会替换try块中抛出的返回或异常。

7

实际上,在任何语言中都是如此...finally语句块总是在return语句之前执行,无论该return语句在方法体中的位置如何。如果不是这种情况,finally块就没有太多意义。


6

是的,因为没有控制语句可以阻止finally被执行。

以下是一个参考示例,其中所有代码块都将被执行:

| x | Current result | Code 
|---|----------------|------ - - -
|   |                |     
|   |                | public static int finallyTest() {
| 3 |                |     int x = 3;
|   |                |     try {
|   |                |        try {
| 4 |                |             x++;
| 4 | return 4       |             return x;
|   |                |         } finally {
| 3 |                |             x--;
| 3 | throw          |             throw new RuntimeException("Ahh!");
|   |                |         }
|   |                |     } catch (RuntimeException e) {
| 4 | return 4       |         return ++x;
|   |                |     } finally {
| 3 |                |         x--;
|   |                |     }
|   |                | }
|   |                |
|---|----------------|------ - - -
|   | Result: 4      |

在下面的变体中,return x;将被跳过。结果仍然是4:
public static int finallyTest() {
    int x = 3;
    try {
        try {
            x++;
            if (true) throw new RuntimeException("Ahh!");
            return x; // skipped
        } finally {
            x--;
        }
    } catch (RuntimeException e) {
        return ++x;
    } finally {
        x--;
    }
}

当然,引用会跟踪它们的状态。这个例子返回一个值为4的引用:

static class IntRef { public int value; }
public static IntRef finallyTest() {
    IntRef x = new IntRef();
    x.value = 3;
    try {
        return x;
    } finally {
        x.value++; // will be tracked even after return
    }
}

6

try-catch-finally是处理异常情况的关键字。
作为普通的解释。

try {
     //code statements
     //exception thrown here
     //lines not reached if exception thrown
} catch (Exception e) {
    //lines reached only when exception is thrown
} finally {
    // always executed when the try block is exited
    //independent of an exception thrown or not
}

finally代码块可以在以下情况下阻止执行...

  • 当您调用System.exit(0);
  • 如果JVM退出
  • JVM中的错误

6

如果抛出异常,则会执行finally块。如果没有抛出异常,则会执行finally块。如果捕获了异常,则会执行finally块。如果没有捕获异常,则会执行finally块。

唯一不执行finally块的情况是JVM退出。


6

如果您不处理异常,在终止程序之前,JVM会执行finally块。只有在程序的正常执行失败导致程序终止时,才不会执行finally块,这可能是由于以下原因之一:

  1. 引起导致进程中止的致命错误。

  2. 由于内存损坏而导致程序终止。

  3. 通过调用System.exit()。

  4. 如果程序进入无限循环。


5
是的,这里写道:如果在try或catch代码正在执行时JVM退出,则可能不会执行finally块。同样地,如果执行try或catch代码的线程被中断或终止,则即使整个应用程序继续运行,finally块也可能不会执行。

3
所以当你说“是”时,你的意思是“不是”? - user207421

5
在一些特定的情况下,finally块不会在return语句之后被调用:如果先调用System.exit()方法或JVM崩溃了。让我尽可能简单地回答你的问题。
规则1:finally块总是会运行(虽然有例外情况,但我们现在先遵守这个规则)。
规则2:当控制流程离开try块或catch块时,finally块中的语句将被执行。控制流程可以由正常执行、break、continue、goto、return语句的执行,或者异常的传播引起。
特别是在return语句的情况下(因为这是问题的关键),控制流必须离开调用方法,并因此调用相应try-finally结构的finally块。return语句在finally块之后执行。
如果在finally块中也有return语句,则肯定会覆盖try块中挂起的return语句,因为它清除了调用堆栈。
你可以在这里查看更好的解释:http://msdn.microsoft.com/en-us/... 在所有高级语言中,概念基本上都是相同的。

4
试试这段代码,你会明白finally块中的代码在return语句之后执行
public class TestTryCatchFinally {
    static int x = 0;
    
    public static void main(String[] args) {
        System.out.println(f1());
        System.out.println(f2());
    }
    
    public static int f1() {
        try {
            x = 1;
            return x;
        } finally {
            x = 2;
        }
    }
    
    public static int f2() {
        return x;
    }
}

4

finally块始终会执行,无论是否处理异常。如果try块之前发生任何异常,则finally块将不会执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接