5

大多数时候,我看到 finally 块的唯一用途是

FileInputStream f;
try{
    f= new FileInputStream("sample.txt");
    //something that uses f and sometimes throws an exception
}
catch(IOException ex){
    /* Handle it somehow */
}
finally{
    f.close();
}

我的问题是,如果 f 的作用域以封闭块结束,为什么我们需要在 finally 中关闭它?

4

5 回答 5

20

因为垃圾收集与资源清理不是一回事。

例如,如果您有一个超出范围的 JDBC Connection 对象,则不会向数据库服务器发送信号来指示不再需要打开的游标和连接。如果没有这些消息,您最终会耗尽可用的游标和连接的数量。

与文件句柄和任何其他资源相同。自己清理干净。

于 2011-10-04T17:59:19.730 回答
6

好吧,您举了一个不好的例子-我怀疑您的意思是FileInputStream-但基本原因是Java没有确定性终结。

变量 的范围以f它在其中声明的块(不是try块)结束,但这并不意味着不再需要对该对象的“实时”引用——垃圾收集器既不会终结对象,也不会进行垃圾收集它以任何确定的方式。

除非您想让资源闲置任意长度(并延迟垃圾收集,因为终结器需要在最终释放内存之前进行额外的收集),否则您应该明确关闭资源。

基本上,Java 不像C++那样支持 RAII;您不应该尝试像使用 C++ 一样使用它。

于 2011-10-04T17:59:29.983 回答
2

因为 finally 每次都会被调用,即使你得到一个异常。finally 块确保您关闭文件/连接。

于 2011-10-04T18:01:51.797 回答
0

原因是 Java 不保证对象的特定引用一旦超出范围就会被垃圾回收。所以对于引用有限系统资源的对象,比如文件描述符,仅仅等待垃圾回收是不够的。

但请注意,这java.io.File实际上不是这样的对象。

于 2011-10-04T18:00:06.383 回答
0

我们通过 try catch finally 处理异常,finally 每次执行时都会阻塞,但不能保证 catch,因为 catch 阻塞只有在传入参数匹配的异常时才会执行。例如,如果我们打开了任何数据库连接,那么我们必须在离开之前关闭它,这必须在 finally 中实现。

于 2011-10-04T18:04:21.423 回答