8

我认为以下示例;但无法弄清楚 finally 块的重要性是什么。你能告诉我这两个代码示例的执行有什么不同吗?一个现实生活中的例子也会有所帮助。

样品 1:

    try{
       // some code 1
    }catch(Exception ex){
       // print exception   
    }finally{
       // some code 2            
    }

样本 2:

    try{
      // some code 1
    }catch(Exception ex){
      // print exception   
    }
    // some code 2
4

7 回答 7

17

您提供的两个片段有很大的不同,例如,当catch块本身引发异常时,该finally块仍将按其语义执行。

这是以下代码段打印"Finally!",但不是"What about me???"

    try {
        throw null;     // throws NullPointerException!
    } catch (Exception e) {
        int oops = 1/0; // throws ArithmeticException!
    } finally {
        System.out.println("Finally!"); // still gets executed!
    }
    System.out.println("What about me???"); // doesn't get executed!

一般来说,finally一个try块的几乎总是被执行。try该块后面的任何代码都没有这样的保证。


但是如果我的catch块只是一个简单的print语句呢?

仍然不能保证它不会发生任何throw事情。例如,异常详细消息的构造仍然可能出错。

即使您尽最大努力保证catch代码是“安全的”并且try语句后面的代码将始终被执行,那么问题就会变成“为什么?”。为什么要避免finally但又如此努力地复制其语义?

finally语义得到保证,不需要代码作者或读者的举证责任。正因为如此,使用块来放置强制性的“清理”代码是惯用的。finally使用finally保证正确性并增强可写性和可读性。

于 2010-06-30T08:56:12.720 回答
8

finally即使例如抛出了一个块,该块也会被执行,在您的示例中Error,它不会被块捕获。catch因此,您可以将清理代码放在finally应该始终运行的块中,而不管tryandcatch块中的操作结果如何。

请注意,通常catch块捕获更具体类型的异常 - 通常只检查异常 - 所以在大多数情况下,上面两个代码示例之间的差异是非常明确的。

更新:你可能会说你的catch块永远不会抛出异常,所以finally不需要。但是,请注意两点:

  • 这只是代码的当前状态,将来可能会发生变化——你能保证在块中添加一些可能引发异常的代码的未来程序员catch会记得将清理代码放在finally块中吗?
  • try-catch-finally是一种编程习惯,它使阅读代码的人更容易理解正在发生的事情。如果你不使用常见的成语,你就有误解的风险,因此长期存在错误。
于 2010-06-30T08:53:55.047 回答
2

您使用该finally块来清理和运行任何应该运行的代码,无论是否抛出(和捕获)异常。这包括您在catch块中的代码。

于 2010-06-30T08:53:30.490 回答
1

当我们想要释放我们在 try 块中使用的资源时,它会很有帮助。因此,在任何情况下都可以执行它们而不会丢失的唯一地方是 finally 块。因为如果抛出异常,java 不会执行紧随其后的代码。它直接跳转到catch块。

于 2010-06-30T08:58:24.520 回答
0

如果 try 块中的语句抛出未经检查的异常,finally 块将被执行,允许程序员采取相关操作。

于 2010-06-30T09:08:22.670 回答
0

在现实生活中,finally 块用于关闭打开的资源,即使发生异常也是如此。例如,当您读取(或写入)文件时,当您访问数据库时等。

public void readFile(String fileName) {
    FileReader fr;
    BufferedFileReader bfr;

    try {
        fr = new FileReader(fileName);
        bfr = new BufferedFileReader(fr);
        // ...
    } catch (IOException ioe) {
        // ...
    } finally {
        // TO ENSURE THAT THE READERS ARE CLOSED IN ALL CASES
        if (bfr != null) { 
            try {
                bfr.close();
            } catch (IOException ignoredIOE) {}
        }
        if (fr != null) { 
            try {
                fr.close();
            } catch (IOException ignoredIOE) {}
        }
    }
}
于 2010-06-30T10:30:37.333 回答
0

请注意,您甚至可以在没有捕获的情况下进行 try-finally:

try{
   // some code 
}finally{
   // cleanup code
}

因此,一个示例可能是希望将异常传播给调用者的方法,但仍需要清理代码,例如释放外观。

于 2010-06-30T09:00:13.813 回答