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

Elo*_*off 8 java java-7

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

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

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

人们可以把它写成:

try (InputStreamReader reader = new InputStreamReader(...))
Run Code Online (Sandbox Code Playgroud)

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

这里有最好的做法吗?

fge*_*fge 12

这意味着InputStreamReader永远不会关闭

嗯?在你的代码中......它肯定会处理资源流的.close().请参阅下面的更多细节...

正如@SotiriosDelimanolis所提到的,您可以在try-with-resources语句的"资源块"中声明多个资源.

你在这里有另一个问题:.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
}
Run Code Online (Sandbox Code Playgroud)

但是有一点非常重要,需要考虑 ......

Closeable确实延伸AutoCloseable,是的; 实际上它只是抛出(IOExceptionvs Exception)异常,"签名明智" .但行为存在根本差异.

从javadoc AutoCloseable.close()(强调我的):

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

事实上,javadoc Closeable很明显:

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

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

  • 通过合同,a Closeable还负责处理与之相关的所有资源; 所以,如果你关闭一个BufferedReader包裹了一个包裹的Reader包裹InputStream,那三个都关闭了;
  • 如果你.close()不止一次打电话,没有进一步的副作用.

当然,这也意味着您可以选择偏执选项并保留对所有 Closeable资源的引用并将它们全部关闭; 但要注意你是否有AutoCloseable资源混合而不是Closeable!


Sot*_*lis 5

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

没错(虽然不太可能,但InputStreamReader构造函数实际上并没有做太多事情)。

try-with-resources允许声明尽可能多的资源,只要你愿意。为包装的资源声明一个,为InputStreamReader.

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

请注意,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)
) {
Run Code Online (Sandbox Code Playgroud)

与解释

在此示例中,try-with-resources 语句包含两个用分号分隔的声明:ZipFileBufferedWriter。当直接跟随它的代码块终止时,无论是正常情况还是由于异常,都将按此顺序自动调用BufferedWriterZipFile对象的关闭方法。请注意,资源的 close 方法以其创建的相反顺序调用。