Java 使用资源尝试使用InputStreamReader包装流的位置?
我可能想得太多了,但我只是写了代码:Java 使用资源尝试使用InputStreamReader包装流的位置?,java,java-7,Java,Java 7,我可能想得太多了,但我只是写了代码: try (InputStream in = ModelCodeGenerator.class.getClassLoader().getResourceAsStream("/model.java.txt")) { modelTemplate = new SimpleTemplate(CharStreams.toString(new InputStreamReader(in, "ascii"))); } 这意味着InputStreamReader永远不
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++中的常见问题是调用其他构造函数的构造函数。异常可能导致内存/资源泄漏
这里有最佳实践吗
但这似乎更糟。如果InputStreamReader
出于某种原因抛出,则
InputStream
永远不会被关闭,对吗
这是正确的(虽然不太可能,但是InputStreamReader
构造函数实际上做不了多少事情)
允许您声明任意数量的资源。声明一个用于包装的资源,另一个用于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
。当直接跟随它的代码块
通常或由于异常而终止关闭
BufferedWriter
和ZipFile
对象的方法是自动生成的
按此顺序调用。请注意,资源的close方法是
以与他们的创造相反的顺序被召唤
这意味着InputStreamReader从未关闭
嗯??在你的代码中它是。。。它当然也会处理资源流的.close()。有关更多详细信息,请参见下文
但是,您可以在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
}
有一个非常重要的一点需要考虑,但是
Closeable
扩展了AutoCloseable
,是;事实上,它只是通过抛出异常(IOException
vsexception
)而与“签名方式”有所不同。但在行为上有一个根本的区别
从AutoCloseable
的.close()
的javadoc(强调我的):
请注意,与Closeable的close方法不同,此close方法不要求是幂等的。换句话说,多次调用此close方法可能会产生一些明显的副作用,这与Closeable.close不同,Closeable.close要求在多次调用时不起作用。但是,强烈鼓励此接口的实现者使其紧密方法幂等
事实上,Closeable
的javadoc很清楚这一点:
关闭此流并释放与之关联的所有系统资源。如果流已关闭,则调用此方法无效
你有两点非常重要:
- 根据合同,
还负责与之相关的所有资源;因此,如果关闭一个可关闭的
,该读取器封装一个缓冲读取器
,该读取器封装一个读取器
,这三个读取器都将关闭李>输入流
- 如果您多次调用
,则不会产生进一步的副作用.close()
当然,这也意味着您可以选择偏执选项,保留对所有
Closeable
资源的引用并将其全部关闭;但是,如果您的组合中有可自动关闭的资源,而这些资源不是可关闭的
,请小心 我想关闭这两个是安全的方法。我们知道,这有点过头了,但依赖于实现细节的安全性是一种糟糕的做法。顺便说一下,NPE很好。更新了完整的答案!谢谢你澄清你的答案!当检查NPE时,代码很明显,您只需要在try with resources中使用InputStreamReader,因为当该自动关闭时,它将关闭底层流,正如您正确指出的那样。但是,引发此问题的行为是您尝试的情况(reader=new InputStreamReader(getResourceAsStream(“…”))。在这种情况下,如果在构造InputStreamReader的过程中出现异常,那么我想象reader.close()从未被调用(reader还不存在),但流已打开,没有命名引用,并且将永远不会关闭,可能的终结器除外。在我看来,这是一个容易犯的错误,也是一个很难抓住的错误。C++更常见,是的,你说得很对。只有在try with resources块中“安全声明”的资源才会安全关闭,如果您将它们“链接”起来,则情况并非如此。