5

背景

我在IOUtils上使用了一个很好的函数,叫做 "closeQuietly" ,它关闭流,不管里面有什么。

例如:

InputStream input = null;
try
  {
  ...
  input = connection.getInputStream();
  ...
  } 
catch(Exception e)
  {
  }
finally
  {
  IOUtils.closeQuietly(input);
  }

不知何故,当我在 finally 块中调用它时,它也隐藏了 Eclipse 上的警告,即“资源泄漏:'input' is not closed at this location”。

这意味着在上面的代码中,没有这样的警告。

问题

我不明白它如何将警告隐藏在自身的“外部世界”上。

我试过的

我试图通过复制这个库的代码来检查它(这里的例子),但是当我在新类上使用它时会出现警告。这没有意义...

这是我创建的示例代码,用于显示警告将发生在您自己的类上:

public class MyIOUtils {
    public static void closeQuietly(final InputStream input) {
        if (input == null)
            return;
        try {
            input.close();
        } catch (final IOException ioe) {
        }
    }

    public static void closeQuietly(final OutputStream output) {
        if (output == null)
            return;
        try {
            output.close();
        } catch (final IOException ioe) {
        }
    }
}

用法:

public class Test {
    public void test() {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("dummyFile.txt");
            int t = 0;
            --t;
            if (t < 0)
                return; // here you will get a warning
        } catch (final FileNotFoundException e) {
        } finally {
            MyIOUtils.closeQuietly(inputStream);
        }
    }
}

这是我看到的,包括我正在安装的 Eclipse 版本:

在此处输入图像描述

问题

它是如何做到的?

4

2 回答 2

3

那么为什么它适用于 IOUtils 呢?eclipse 团队做了一些非常简单的事情——他们对方法进行了硬编码!在以前的 Eclipse 版本中,警告也存在,但是从 4.​​3 M4 版本开始,自从他们修复它以来它就消失了:

Released for 4.3 M4 via commit 277792ba446c3713bcfdc898c37875d45fc06c18.

The fix covers the following well-known methods:
- com.google.common.io.Closeables.closeQuietly(Closeable)
- com.google.common.io.Closeables.close(Closeable,boolean)
- org.apache.commons.io.IOUtils.closeQuietly(Closeable)

有关详细信息,请参见此处-尤其是最后的评论...

更新:那么这对你意味着什么?您必须使用上述方法之一或接受警告。检查基本不复杂,不检查下一级。

更新二: 他们基本上对文件名进行了硬编码。也许使用源代码更容易理解。想象一下,这是检查警告的Eclipse 代码:

public boolean showResourceWarning(){

//do somestuff to detect whether a potential ressource warning is shown
...
    if(resourceLeakWarning){
      if(this.checkForExceptions()){
       return false;
      }
    }
 return resourceLeakWarning;
}

private boolean checkForExceptions(){
    if(name.equals("org.apache.commons.io.IOUtils.closeQuietly(Closeable)"){
     return true;
    }
    if(name.equals("com.google.common.io.Closeables.close(Closeable,boolean)")){
     return true;
    }
    if(name.equals("org.apache.commons.io.IOUtils.closeQuietly(Closeable)")){
     return true;
    }
    // code executed for your method:
    return false;
}

=> 结果是,您没有机会删除警告,而直接使用 close() (不在子方法中!)或使用上面列出的三种方法之一。

更新三:看看下面的类TypeConstants.java。你看到那里的硬连线名称吗?如果你想让它与你的代码一起工作,你需要在那里添加你的类和方法名,然后重新编译 eclipse。然后从第 90 行开始查看MessageSend.java类。

于 2014-10-24T13:09:28.143 回答
0

我无法在我的 Eclipse 安装中重现此问题,因此无法测试我的解释。然而,这是我们在http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CC0QFjAA&url=http%3A%2F%2Fhelp.eclipse.org% 2Fjuno%2Ftopic%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-avoiding_resource_leaks.htm&ei=r-TeUvumDsXxoASN8IG4CA&usg=AFQjCNHeI8Ojm5VDlFo_9s-V3IvR7qYokw&sig2=jp9_tF3VbR0u_w6OHY3KOw12&

资源包装器和无资源可关闭对象

JDK 定义了一些实现 Closeable 但不直接表示操作系统级别的资源的类。

java.io.StringReader 是不需要调用 close() 的可关闭对象的示例,因为没有保留需要清理的操作系统资源。该分析使用显式白名单来检测 java.io 中属于此类别的类。不会针对这些类发出资源泄漏警告。

像 java.io.BufferedInputStream 这样的类的实例是另一个资源的包装器(包装器可以应用于多个级别)。这些对象也不直接代表操作系统资源。如果包装的资源已关闭,则包装器不需要关闭。相反,如果包装器被关闭,这将包括被包装资源的关闭。该分析具有用于检测包装器资源的第二个白名单,并将识别底层实际资源是直接关闭还是通过包装器间接关闭。任何一种都足以消除有关资源泄漏的警告。白名单包含来自 java.io、java.util.zip、java.security、java.beans 和 java.sound.sampled 的类。

提示:通常最好/最安全的是关闭最外层的包装器,而不是包装的资源。

根据 IOUtils 文档,此类中读取流的所有方法都在内部缓冲。这意味着没有理由使用 BufferedInputStream 或 BufferedReader。4K 的默认缓冲区大小已被证明在测试中是有效的。

于 2014-01-21T21:38:33.463 回答