Java 这个finally子句包含close()调用的原因是什么
我正在学习在线java课程 在关于I/O的章节中,介绍了以下代码和以下声明: 顺便说一下,在本程序的末尾,您将在try语句中找到finally子句的第一个有用示例。当计算机执行try语句时,无论发生什么情况,其finally子句中的命令都保证被执行 该程序位于第节的末尾,是一个简单的程序,只需从文件中读取一些数字,然后按相反顺序写入 主方法中的相关代码是(数据是读卡器,结果是写卡器): 所以我想知道为什么finally子句在这种情况下很有用,因为try或catch子句没有其他退出点。关闭方法不能只在主体中吗Java 这个finally子句包含close()调用的原因是什么,java,exception-handling,try-catch-finally,Java,Exception Handling,Try Catch Finally,我正在学习在线java课程 在关于I/O的章节中,介绍了以下代码和以下声明: 顺便说一下,在本程序的末尾,您将在try语句中找到finally子句的第一个有用示例。当计算机执行try语句时,无论发生什么情况,其finally子句中的命令都保证被执行 该程序位于第节的末尾,是一个简单的程序,只需从文件中读取一些数字,然后按相反顺序写入 主方法中的相关代码是(数据是读卡器,结果是写卡器): 所以我想知道为什么finally子句在这种情况下很有用,因为try或catch子句没有其他退出点。关闭方法不能
我想这可能是因为理论上可能存在其他运行时异常,这些异常会使程序崩溃,然后使读写器无法关闭,但程序崩溃的事实不会让它们关闭吗?在抛出或未抛出异常的情况下,
finally
子句将确保数据流
和结果流
均已关闭。否则,它们可能无法关闭。来自Java文档:
当try块退出时,finally块始终执行。这确保即使发生意外异常,也会执行finally块。但最后,它不仅仅适用于异常处理——它允许程序员避免因返回、继续或中断而意外绕过清理代码。将清理代码放在finally块中始终是一种好的做法,即使在没有预期异常的情况下也是如此
以及您对以下方面的关注:
程序崩溃这一事实无论如何都让他们无法接受
资源是在
OS
级别分配的,而不是在您的程序中分配的,因此如果您的程序没有机会清理,那么资源将在没有真正使用的情况下分配。这是一个非常简单的原因:这是最安全的方法,在Java 7之前尝试使用资源,确保即使捕获到异常,您的资源也已关闭
考虑一下如果你这样做了会发生什么:
try {
// some code, then
resource.close();
} catch (SomeException e) {
// etc
}
如果在关闭资源之前抛出了SomeException
,则可能会泄漏资源。另一方面,将resource.close()
放入finally
,可以保证无论发生什么情况,它都会被关闭
对于Java 7,您可以使用以下内容:
try (
final InputStream in = Files.newInputStream(Paths.get("somefile"));
// Others
) {
// work with "in" and others
} catch (Whatever e) {
}
然后,您的资源将在catch
之前关闭
另外,使用Java6关闭资源最安全的方法是使用番石榴。如果出现
RuntimeException
,finally将被执行,从而关闭资源,这在理论上是不正确的。这是一个实际情况
此外,即使发生了
IOException
(或您捕获的许多其他异常)finally
子句防止您多次编写相同的代码来关闭。您的想法是正确的:finally块将关闭资源,即使发生意外异常
如果这样的异常使整个应用程序崩溃,那么这一点也不重要,这一点您是对的,但是通过查看此代码,您无法确定是否存在这种情况。可能还有其他异常处理程序捕获该异常,因此将结束逻辑放在finally块中是一种良好且正确的做法
请注意,仍然可能有一个bug隐藏:如果data.close()
抛出异常,result.close()
将永远不会被调用
根据您的环境,对于如何修复bug有不同的风格
- 在Java7FF中,您可以使用
- 如果您使用的是Spring,那么可能会有一个与
- 如果这些都不适用,是的,您必须在finally中尝试/finally。别闹了。您绝对应该至少将其提取到注释中建议的方法中
- 概念上更清晰但在JavaPre8中更冗长的是实现。如果您没有与scala/clojure/haskell开发人员一起工作,那么可能会比其他任何东西更令人困惑
CheckedException
类似IOException
的异常时,必须关闭所有资源。这是因为:
close()
资源,以便
刷新缓冲区,即保存更改try {
BufferedReader br = new BufferredReader (new FileReader("Example.txt"));
ArrayList<String> lines = new ArrayList<>();
String line;
while ( (line = br.readLine()) != null ) {
lines.add(line);
}
catch (IOException ie) {
//Error handling.
} finally {
br.close();
}
现在,不需要
finally
块,因为BufferedReader
实现了。顾名思义,当try(…)
块离开时,它会自动关闭缓冲区。如果程序在此之后终止,那么是的,这也会关闭I/O资源
但许多程序不会终止。有些设备必须24/7运行多年。因此,正确清理您的资源是必不可少的
不幸的是,Java<7只提供了一种自动的内存清理机制(垃圾收集)。使用Java7,您将得到一个新的“”来尝试填补漏洞
除非您可以使用此版本,否则您必须自己进行清理
也就是说,上面的代码仍然有缺陷:close()
本身会引发异常,因此一些I/O资源可能仍然存在。您应该使用以下工具:
Fi
try {
BufferedReader br = new BufferredReader (new FileReader("Example.txt"));
ArrayList<String> lines = new ArrayList<>();
String line;
while ( (line = br.readLine()) != null ) {
lines.add(line);
}
catch (IOException ie) {
//Error handling.
} finally {
br.close();
}
try (BufferedReader br = new BufferredReader (new FileReader("Example.txt"));) {
ArrayList<String> lines = new ArrayList<>();
String line;
while ( (line = br.readLine()) != null ) {
lines.add(line);
}
catch (IOException ie) {
//Error handling.
}
Reader reader = null;
try {
reader = ...open...
...use reader...
} finally {
IOUtils.closeQuietly(reader);
}