Java 资源管理:了解 Findbugs 结果

Posted

技术标签:

【中文标题】Java 资源管理:了解 Findbugs 结果【英文标题】:Java resource management: understanding Findbugs results 【发布时间】:2011-01-27 08:44:18 【问题描述】:

Findbugs 让我对打开两个 Closeable 实例的方法感到不满,但我不明白为什么。

来源

public static void sourceXmlToBeautifiedXml(File input, File output)
        throws TransformerException, IOException, JAXBException 

    FileReader fileReader = new FileReader(input);
    FileWriter fileWriter = new FileWriter(output);

    try 
        // may throw something
        sourceXmlToBeautifiedXml(fileReader, fileWriter);
     finally 
        try 
            fileReader.close();
         finally 
            fileWriter.close();
        
    

查找错误分析

Findbugs 告诉我

Method [...] may fail to clean up java.io.Reader [...]

并指向带有FileReader fileReader = ...的行

问题

谁错了:我还是 Findbugs?

【问题讨论】:

【参考方案1】:

FindBugs 正确:如果 FileWriter 的构造函数抛出异常,文件阅读器不会被关闭。要验证这一点,请尝试为 output 传递一个无效的文件名。

我会这样做:

    FileReader fileReader = new FileReader(input);

    try 
        FileWriter fileWriter = new FileWriter(output);
        try 
            // may throw something
            sourceXmlToBeautifiedXml(fileReader, fileWriter);
         finally 
            fileWriter.close();
        
     finally 
        fileReader.close();
    

请注意,可以改进对关闭时抛出的异常的处理,因为通过抛出异常离开 finally 块将导致 try 语句通过抛出该异常而终止,吞下 try 块中抛出的任何异常,这通常对调试更有用。有关如何避免这种情况的简单方法,请参阅 duffymo 的回答。

编辑:从 Java 7 开始,我们可以使用 try-with-resources 语句,它允许正确和简洁地处理这些极端情况:

try (
    FileReader fileReader = new FileReader(input); 
    FileWriter fileWriter = new FileWriter(output)
) 
    // may throw something
    sourceXmlToBeautifiedXml(fileReader, fileWriter);

【讨论】:

+1 是唯一一个注意到 constructor 可以抛出的人。就个人而言,我会在 try 内调用 ctors(将变量显式初始化为 null 外),然后在 finally 内使用 Jakarta IOUtils.closeQuietly() FileReaderFileWriter 的实际实现非常糟糕,以至于在打开文件后它们可能会抛出异常(并且由于它来自构造函数,因此您没有关闭的引用自己做)。另请注意,您正在隐式使用当时恰好配置为默认值的任何字符集编码,这绝不是一个好主意。 很好 - 我要 +1 不是因为可以改进异常处理,这不仅会导致从 finally 抛出会吞下潜在的 try 异常,而且很可能会导致 close() 异常意义重大。 我在哪里说过它们不重要?我的代码不会抑制它们,是吗?【参考方案2】:

即使对于 findbugs,这也可能很复杂。

try 
   fileReader.close();
 finally 
   fileWriter.close();

在我看来你是对的。

编辑:哇,我以为我会因为说 findbugs 可能出错而被否决!

EDIT:看起来 FindBugs 是对的。不错的收获。

【讨论】:

好吧,如果你说 findbugs 错了,我可能会投反对票,但你说它可以肯定是正确的.【参考方案3】:

我会说是你。

我会在单独的 try/catch 块中关闭这两个资源。我会创建静态方法来帮助我:

public static void sourceXmlToBeautifiedXml(File input, File output)
        throws TransformerException, IOException, JAXBException 

    FileReader fileReader = new FileReader(input);
    FileWriter fileWriter = new FileWriter(output);

    try 
        // may throw something
        sourceXmlToBeautifiedXml(fileReader, fileWriter);
     finally 
        close(fileReader);
        close(fileWriter);
    



// same for reader & writer
public static void close(InputStream s)

    try
     
       if (s != null)
       
           s.close();
       
    
    catch (IOException e)
    
        e.printStackTrace();
    

【讨论】:

嗯,我不敢相信这是关闭多个资源时的常见模式。这有什么模式吗? 肯定有 JDBC。 ResultSet、Statement 和 Connection 很常见。 我不知道是不是“模式”,但是我写的就是那个静态方法。 这个答案只是令人困惑 - 没有解决已接受的答案中解决的真正问题。请考虑编辑它-1【参考方案4】:

我认为 findbugs 是对的。

 finally 
    try 
        fileReader.close();
     finally 
        fileWriter.close();
    

在此块中,您尝试关闭 FileReader。然而,这可能会引发异常,并在嵌套的最后关闭 fileWriter。您是否尝试在同一个 finally 块中关闭两个阅读器?那么 findbugs 怎么说呢?

 finally 
    try 
        fileReader.close();
        fileWriter.close();
     finally 
        //dunno maybe log that something went wrong.
    

【讨论】:

如果 fileReader.close() 抛出 IOException,fileWriter 将永远不会被关闭。 您的批评者适用于您的第二个代码示例。 -- 是的fileReader.close() 可能会抛出IOExceptioon,这就是为什么在我的示例中fileWriter.close 位于finally 块中:如果关闭fileReader 失败,则无论如何都会关闭fileWriter。 该死。得到我。经验法则:在你喝第一杯咖啡之前不要去 *** ;-) 请删除这个 - 不添加任何值 -1

以上是关于Java 资源管理:了解 Findbugs 结果的主要内容,如果未能解决你的问题,请参考以下文章

项目管理_FindBugs的使用

idea 安装findBugs 可以做代码扫描,也可以导出扫描结果生成扫描报告

jenkins+findbugs

Java代码Bug分析插件 FindBugs

为啥我在 SonarQube 上看不到 Findbugs 的错误?

时 间 投 资 法