0

每当我看到 Java 6 Stream 处理时,它几乎都是这样完成的:

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不会被分配,那么无论如何也没有什么可关闭的,不是吗?

4

2 回答 2

4

我同意你的看法。

分配的额外步骤null是不必要且丑陋的。你甚至可以做streamfinal。

我唯一会写这样的东西是如果你有多个资源需要清理(经常发生在 JDBC 上),并且你想避免多个嵌套的 try/finally 块(但通常我还是会选择那些)。

在 Java 7 中,您可以使用 try-with 结构。

于 2013-07-12T02:16:48.870 回答
0

每次您使用类似的构造检索 InputStream

InputStream stream = connection.openConnection();

有三种可能的结果:方法要么返回正确的InputStream,要么返回null,要么抛出异常。

让我们看看所有三种可能性:

1) 该方法返回了正确的输入流。

在这种情况下,try 块只会继续,如果它没有遇到任何其他问题(也就是异常),它通常会在执行 finally 块之后结束。

2) 该方法返回null。

在这种情况下,您还应该在 try 块内进行空检查。如果是这样,您的 try 块通常什么都不做,finally 块也必须进行空检查。否则你的 finally 块会抛出一个 NPE。

如果您不防范 null 返回,则 try 块内的代码将抛出 NPE(我假设流变量在那里使用)。在这种情况下,finally 块将被执行并再次抛出一个 NPE,如果它没有 null 检查。在后一种情况下,只有 finally 块中的第二个 NPE 实际上被抛出给调用者。

3) 检索输入流的方法调用抛出异常。

在这种情况下,try 块将结束,这将立即导致 finally 块执行,然后该方法将突然结束。但有哪个例外?那要看。

考虑抛出的异常是一个 IOException,在大多数情况下都会被抛出。首先,变量仍然会有空引用!如果 finally 块没有空检查,那么它会再次抛出 NPE。在这种情况下,第一个异常(IOE)将被遗忘,因为只有 NPE 会被传递给您的方法的被调用方。这不是一个好主意。

总而言之,空检查确实是必要的。

现在 Java 7 带有它的 try-with-resources 结构。这确实是一个更好的机制,因为它有一个隐式的 finally 块,其中流被关闭。如果 try 块中存在异常,并且隐式 finally 块也抛出异常,则第一个异常(来自 try 块内部)将被传递给调用者。这更合适。而且语法更易读。

于 2013-07-12T14:06:09.433 回答