内联创建的 InputStream 是否被 GC 自动关闭?
Is inline created InputStream closed automatically by GC?
我已经找到了几个类似的问题,但我仍然找不到我的问题的答案。
我知道关闭外部流就足够了,它将关闭在线创建的内部流。
BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
br.close();
考虑下一个例子
Properties props = new Properties();
props.load(new FileInputStream(configPath));
是否应该将 FileInputStream
分配给变量然后显式关闭(或使用 try-with-resource 构造)或者 Java GC 会在 props.load()
方法后立即自动关闭它调用,因为没有对资源的引用?
Javadoc 指出
The specified stream remains open after this method returns.
所以是的,如果你想编写干净的代码,你应该自己关闭它。 GC 最终将关闭它,if 它开始调用流上的 finalize()
方法(如下所示),但是你 shouldn't rely on that.
始终关闭您的资源,这是唯一可以确定的方法。
/**
* Ensures that the <code>close</code> method of this file input stream is
* called when there are no more references to it.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
必须强调的是,使用像
这样的代码
BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
// you likely insert actual operations on br here
br.close();
强烈建议不要这样做,因为如果流构造和 close()
调用之间的操作抛出异常,则不会发生关闭。
您应该改用“try with resource”结构:
try(BufferedInputStream br = new BufferedInputStream(new FileInputStream(file))) {
// your actual operations on br here
}
这确保即使在try
主体中出现异常,也会调用close()
。但是,此代码依赖于 BufferedInputStream
的 close()
方法将调用 FileInputStream
的 close()
方法这一已知事实,但这在构造BufferedInputStream
已经完成。如果 BufferedInputStream
的构造函数抛出异常,它的 close()
方法将不会被调用,因为没有对象可以调用 close()
on.
一个真正安全的解决方案是
try(FileInputStream fis = new FileInputStream(file);
BufferedInputStream br = new BufferedInputStream(fis)) {
// your actual operations on br here
}
即使 BufferedInputStream
的构造函数抛出异常,也会关闭 FileInputStream
。这在这里看起来像是一个罕见的极端情况,因为在该构造函数中唯一可能出错的是缓冲区分配,它可能会抛出 OutOfMemoryError
,无论如何在这种情况下你都会遇到很大的麻烦。
但是请考虑这样一个例子
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis)) {
// your actual operations on ois here
}
由于ObjectInputStream
的构造函数已经读取了header,所以可能会抛出IOException
s,而且header也可能无效,同样会引发异常。因此,还有更多可能出错的地方,确保底层 FileInputStream
即使在这些情况下也能正确关闭更为重要。
我已经找到了几个类似的问题,但我仍然找不到我的问题的答案。
我知道关闭外部流就足够了,它将关闭在线创建的内部流。
BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
br.close();
考虑下一个例子
Properties props = new Properties();
props.load(new FileInputStream(configPath));
是否应该将 FileInputStream
分配给变量然后显式关闭(或使用 try-with-resource 构造)或者 Java GC 会在 props.load()
方法后立即自动关闭它调用,因为没有对资源的引用?
Javadoc 指出
The specified stream remains open after this method returns.
所以是的,如果你想编写干净的代码,你应该自己关闭它。 GC 最终将关闭它,if 它开始调用流上的 finalize()
方法(如下所示),但是你 shouldn't rely on that.
始终关闭您的资源,这是唯一可以确定的方法。
/**
* Ensures that the <code>close</code> method of this file input stream is
* called when there are no more references to it.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
必须强调的是,使用像
这样的代码BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
// you likely insert actual operations on br here
br.close();
强烈建议不要这样做,因为如果流构造和 close()
调用之间的操作抛出异常,则不会发生关闭。
您应该改用“try with resource”结构:
try(BufferedInputStream br = new BufferedInputStream(new FileInputStream(file))) {
// your actual operations on br here
}
这确保即使在try
主体中出现异常,也会调用close()
。但是,此代码依赖于 BufferedInputStream
的 close()
方法将调用 FileInputStream
的 close()
方法这一已知事实,但这在构造BufferedInputStream
已经完成。如果 BufferedInputStream
的构造函数抛出异常,它的 close()
方法将不会被调用,因为没有对象可以调用 close()
on.
一个真正安全的解决方案是
try(FileInputStream fis = new FileInputStream(file);
BufferedInputStream br = new BufferedInputStream(fis)) {
// your actual operations on br here
}
即使 BufferedInputStream
的构造函数抛出异常,也会关闭 FileInputStream
。这在这里看起来像是一个罕见的极端情况,因为在该构造函数中唯一可能出错的是缓冲区分配,它可能会抛出 OutOfMemoryError
,无论如何在这种情况下你都会遇到很大的麻烦。
但是请考虑这样一个例子
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis)) {
// your actual operations on ois here
}
由于ObjectInputStream
的构造函数已经读取了header,所以可能会抛出IOException
s,而且header也可能无效,同样会引发异常。因此,还有更多可能出错的地方,确保底层 FileInputStream
即使在这些情况下也能正确关闭更为重要。