【问题标题】:Java resource management: understanding Findbugs resultsJava 资源管理:了解 Findbugs 结果
【发布时间】: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?

【问题讨论】:

    标签: java resources 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。
    • 该死。得到我。经验法则:在你喝第一杯咖啡之前不要去 stackoverflow ;-)
    • 请删除这个 - 不添加任何值 -1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    相关资源
    最近更新 更多