如何关闭Java流?
每当我看到Java 6流处理时,都是这样做的:
public void myMethod() throws Exception
{
InputStream stream = null;
try
{
stream = connection.openConnection();
...
}
finally
{
if( stream != null )
{
stream.close();
}
}
}
但我不明白为什么这是必要的。这不是同样的工作方式吗
public void myMethod() throws Exception
{
InputStream stream = connection.openConnection();
try
{
...
}
finally
{
stream.close();
}
}
如果openConnection()
失败,那么stream
将不会被分配,而且无论如何也没有什么可关闭的,不是吗
# 1 楼答案
每次检索具有以下结构的InputStream时
有三种可能的结果:要么该方法返回正确的
InputStream
,要么返回null
,要么抛出异常让我们看看所有三种可能性:
1)该方法返回了正确的输入流
在这种情况下,try块只是继续,如果它没有遇到任何其他问题(aka异常),它通常在执行finally块之后结束
2)该方法返回null
在这种情况下,您还应该在try块中进行null检查。如果是这样,try块通常不执行任何操作,finally块也必须进行null检查。否则,您的最后一个区块将抛出NPE
如果不防止null返回,try块中的代码将抛出NPE(我假设在那里使用了stream变量)。在这种情况下,将执行finally块,如果没有空检查,它将再次抛出NPE。在后一种情况下,实际上只有来自finally块的第二个NPE被抛出给调用方
3)检索输入流的方法调用引发异常
在这种情况下,try块将结束,这将立即导致finally块执行,然后该方法将突然结束。但哪一个例外?那要看情况
认为抛出异常是IOExExt,在大多数情况下将抛出。首先,变量仍然有空引用!如果finally块没有空检查,那么它将再次抛出一个NPE。在这种情况下,第一个异常(IOE)将被忽略,因为只有NPE将被传递给方法的被调用方。那不是个好主意
总之,空检查确实是必要的
现在是Java7及其try-with-resources结构。这确实是一个更好的机制,因为它有一个隐式finally块,其中流是闭合的。如果try块中存在异常,并且隐式finally块也抛出异常,那么第一个异常(从try块内部)将传递给调用方。那更合适。而且语法更易于阅读
# 2 楼答案
我同意你的看法
带有
null
赋值的额外步骤是不必要的,也是丑陋的。您甚至可以将stream
设为final我唯一会这样写的是,如果您有多个需要清理的资源(JDBC经常使用),并且您希望避免多个嵌套的try/finally块(但通常我还是会使用这些块)
对于Java7,您可以使用try-with构造