3

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 分析

Findbugs 告诉我

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

并指向与FileReader fileReader = ...

问题

谁错了:我还是 Findbugs?

4

4 回答 4

4

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);
}
于 2010-03-14T14:41:45.710 回答
3

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

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

在我看来你是对的。

编辑:哇,我想我会因为说 findbugs 可能是错的而被否决!

编辑:看起来 FindBugs 是对的。很好的收获。

于 2010-03-14T10:58:46.090 回答
0

我会说是你。

我会在单独的 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();
    }
}
于 2010-03-14T10:50:51.883 回答
-1

我认为 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.
    }
}
于 2010-03-14T10:49:05.470 回答