10

我知道有几个类似标题的问题,但他们中的大多数人只是忘记close()在他们的信息流中放置指令。这里不同。

假设我有以下最小示例:

public void test() throws IOException
{
    InputStream in;
    if( file.exists() )
    {
        in = new FileInputStream( file );
    }
    else
    {
        in = new URL( "some url" ).openStream();
    }
    in.close();
}

这在 Eclipse (Juno SR1) 中给了我一个Resource leak: 'in' is never closed警告。但是当我将in.close()移入条件块时,警告消失了:

public void test() throws IOException
{
    InputStream in;
    if( file.exists() )
    {
        in = new GZIPInputStream( new FileInputStream( file ) );
        in.close();
    }
    else
    {
        in = new URL( "some URL" ).openStream();
    }
}

这里发生了什么?

4

6 回答 6

7

由于 IO 异常,您可能会遇到资源泄漏(可能)

尝试执行以下操作:

public void test() throws IOException
{
    InputStream in= null;
    try {
        if( file.exists() )
        {
            // In this case, if the FileInputStream call does not
            // throw a FileNotFoundException (descendant of IOException)
            // it will create the input stream which you are wrapping
            // in a GZIPInputStream (no IO exception on construction)
            in = new GZIPInputStream( new FileInputStream( file ) );
        }
        else
        {
            // Here however, if you are able to create the URL
            // object, "some url" is a valid URL, when you call
            // openStream() you have the potential of creating
            // the input stream. new URL(String spec) will throw
            // a MalformedURLException which is also a descendant of
            // IOException.
            in = new URL( "some url" ).openStream();
        }

        // Do work on the 'in' here 
    } finally {
        if( null != in ) {
            try 
            {
                in.close();
            } catch(IOException ex) {
                // log or fail if you like
            }
        }
    }
}

执行上述操作将确保您已关闭流或至少已尽最大努力这样做。

在您的原始代码中,您声明了 InputStream 但从未初始化。这是一种糟糕的形式。如上所示,将其初始化为 null。我的感觉,我目前没有运行 Juno,是它看到 InputStream 'in',可能会通过所有的障碍和障碍到达你将要使用它的地步。不幸的是,正如有人指出的那样,您的代码例如有点狡​​猾。按照我和@duffymo 的详细说明执行此操作,您将摆脱警告。

于 2013-01-10T10:33:20.307 回答
5

我是这样写的:

public void test() throws IOException
{
    InputStream in = null;
    try {
        if(file.exists()) {
            in = new FileInputStream( file );
        } else {
            in = new URL( "some url" ).openStream();
        }
        // Do something useful with the stream.
    } finally {
        close(in);
    }
}

public static void close(InputStream is) {
    try {
        if (is != null) {
            is.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
于 2013-01-10T10:35:00.917 回答
4

我怀疑警告不正确。它可能正在检查您是否正在关闭同一范围内的流。在第二种情况下,您没有关闭第二个流。

于 2013-01-10T10:31:45.290 回答
0

This same Eclipse reporting can happen when you explicitly throw an exception after you have opened your resource like:

public void method() throws IOException {
   BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
   while (br.ready()) {
      String line = br.readLine():
      if (line.length() > 255) {
         throw new IOException("I am some random IOException");
      }
   }
   br.close();
}

This is some contrived code for demonstration purposes so don't look too hard.

If one were to comment out the line, the warning goes away. Of course, you instead want to make sure that that resource is being closed properly. You could do:

if (line.length() > 255) {
   br.close();
   throw new IOException("I am some random IOException");
}

Do not rely on the Eclipse warnings in this case though. Get in the habit of using the try/finally approach to make sure that resources are correctly and consistently being closed.

于 2014-05-09T14:26:22.683 回答
0

如果文件不存在并且您尝试关闭不存在的文件,则可能不会初始化您的输入流。

您的第二个示例还需要一个 close 语句以避免泄漏。

于 2013-01-10T10:33:37.600 回答
0

我有类似的东西:

InputStream content = httpResponse.getEntity()==null?null:httpResponse.getEntity().getContent();

这给出了同样的警告。但是,如果我像这样离开它:

InputStream content =httpResponse.getEntity().getContent();

我没有收到任何警告。是不是很奇怪还是什么?

- 我希望我的信息能够为原始问题增加知识。谢谢!

于 2015-06-23T07:38:36.860 回答