try-with-resources用InputStreamReader包装流的地方?

时间:2015-01-21 18:37:33

标签: java java-7

我可能会过度思考这个问题,但我刚刚写了代码:

try (InputStream in = ModelCodeGenerator.class.getClassLoader().getResourceAsStream("/model.java.txt"))
{
    modelTemplate = new SimpleTemplate(CharStreams.toString(new InputStreamReader(in, "ascii")));
}

这意味着InputStreamReader永远不会关闭(但在这种情况下,我们知道它的close方法只是关闭了底层的InputStream。)

可以将其写成:

try (InputStreamReader reader = new InputStreamReader(...))

但这似乎更糟。如果由于某种原因抛出InputStreamReader,则InputStream将永远不会被关闭,对吧?这是C ++中的常见问题,其中构造函数调用其他构造函数。例外可能导致内存/资源泄漏。

这里有最好的做法吗?

2 个答案:

答案 0 :(得分:12)

  

这意味着InputStreamReader永远不会关闭

嗯?在你的代码中......它肯定会处理资源流的.close()。有关详细信息,请参见下文...

As @SotiriosDelimanolis mentions但是你可以在"资源块"中声明多个资源。尝试资源声明。

这里有另一个问题:.getResourceAsStream()可以返回null;因此,您可能拥有NPE。

如果我是你,我会这样做:

final URL url = ModelCodeGenerator.class.getClassLoader()
    .getResource("/model.java.txt");

if (url == null)
    throw new IOException("resource not found");

try (
    final InputStream in = url.openStream();
    final Reader reader = new InputStreamReader(in, someCharsetOrDecoder);
) {
    // manipulate resources
}

非常重要的一点要考虑但是......

Closeable确实延长了AutoCloseable,是的;实际上它只是因为抛出的异常(IOException vs Exception)而有所不同,#34;签名明智"但行为存在根本区别。

来自AutoCloseable' s .close()的javadoc(强调我的):

  

请注意,与Closeable的close方法不同,此close方法不需要是幂等的。换句话说,多次调用此close方法可能会产生一些明显的副作用,这与Closeable.close不同,如果多次调用则需要无效。但是,强烈建议强制使用此接口的实现者使其接近的方法具有幂等性。

事实上,Closeable的javadoc对此很清楚:

  

关闭此流并释放与其关联的所有系统资源。如果流已经关闭,则调用此方法无效。

你有两个非常重要的观点:

  • 按合同,Closeable也会处理与之相关的所有资源;所以,如果你关闭一个包裹BufferedReader Reader的{​​{1}},那么这三个都会关闭;
  • 如果您不止一次致电InputStream,则无其他副作用。

当然,这也意味着您可以选择偏执选项并保留对所有 .close()资源的引用并将其全部关闭;但请注意,如果您有Closeable个资源而非AutoCloseable

答案 1 :(得分:4)

  

但这似乎更糟。如果InputStreamReader由于某种原因抛出,那么   InputStream永远不会被关闭,对吧?

那是对的(尽管不太可能,InputStreamReader构造函数并没有真正做很多事情。)

try-with-resources可让您声明尽可能多的资源。为包装的资源声明一个,为InputStreamReader声明另一个。

try (InputStream in = ModelCodeGenerator.class
             .getClassLoader()
             .getResourceAsStream("/model.java.txt");
    InputStreamReader reader = new InputStreamReader(in)) {...}

请注意,getResourceAsStream可能会返回null,这会导致InputStreamReader构造函数抛出NullPointerException。如果您想以不同的方式处理,请调整您检索要包装的资源的方式。

上面链接的教程提供了这个示例

try (
    java.util.zip.ZipFile zf =
         new java.util.zip.ZipFile(zipFileName);
    java.io.BufferedWriter writer = 
        java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {

带有解释

  

在此示例中,try-with-resources语句包含两个   由分号分隔的声明:ZipFile和   BufferedWriter。当代码块直接跟随它   正常或因异常终止,结束   BufferedWriterZipFile个对象的方法是自动的   按此顺序调用。请注意,资源的密切方法是   以他们创造的相反顺序召唤。