如果我有一个使用IO资源的类,例如磁盘平面文件,数据库或其他形式的外部资源,那么在重写的finalize()方法中关闭这些流/连接的优缺点是什么?由GC运行?我虽然这可以利用现有的JVM GC,并减少依赖客户端调用类似closeResources()之类的类方法以及编写类似意大利面的try-catches(嵌套try-catches和ifs)的风险我最不喜欢的编程结构。)
作为一个具体的例子,我有一个简单的文件阅读包装器。该类由String filePath
构造,它将文件读入List<String[]>
。我不想在多个地方关闭BufferedReader
,如果打开文件(catch子句)时出现问题,请关闭它,如果文件读得正常则关闭它。我想放它在一个地方,并确保它始终关闭,无论物体何时获得GC。
这种方法是一种很好的做法,还是我试图在Java的范围内为自己提供太高的便利?
答案 0 :(得分:2)
这不是一个好主意,因为无法保证调用finalize()
方法。
当您的代码完成后,关闭资源会更容易也更好。
如果您不喜欢编写嵌套的try-finally块来正确关闭资源,请使用类似commons-io's IOUtils的内容来静默关闭资源(或编写您自己的简单util方法以静默关闭它们) :
InputStream stream = ...;
try {
...
}
finally {
IOUtils.closeQuietly(stream);
}
答案 1 :(得分:1)
当IO资源是实例变量时,您应该使用finalize()
方法关闭它。
为什么?
因为它是一个实例变量,所以你需要它处于打开状态,因为某些方法会重复使用它。
如果您使用除finalize之外的方法关闭它,那么您正在创建temporal coupling
,这意味着类用户需要知道他必须以某个时间顺序调用某些方法,即A之前的A等。
编辑:
Java文档指出垃圾收集器不能保证在任何特定时间运行,并且只要有任何引用,就不会运行finalize()
宾语。如果引用仍然存在,那就是内存泄漏,编程错误。当资源不是方法的本地资源时,finalize()
是最佳选择。如果资源是方法的本地资源,请在finally
的{{1}}末尾关闭它。
答案 2 :(得分:0)
是的,最后阻止始终是释放连接,I / O Sream等资源的最佳方法。