Input / OutputStreams在销毁时是否关闭?

时间:2009-10-05 21:01:11

标签: java scope

Java中的InputStreams和OutputStreams是否在销毁时关闭()?我完全理解这可能是糟糕的形式(特别是在C和C ++世界),但我很好奇。

另外,假设我有以下代码:

private void foo()
{
    final string file = "bar.txt";
    Properties p = new Properties();
    p.load( new FileInputStream(file) );
    //...
}

无名的FileInputStream在p.load()之后是否超出范围,因此被销毁,有点像C ++范围规则?我试图在Google上搜索java的匿名变量范围,但这并没有达到我想象的范围。

感谢。

5 个答案:

答案 0 :(得分:17)

第一个答案:在Java中没有“破坏”(在C ++意义上)这样的东西。只有垃圾收集器,当它看到一个准备收集的对象时,可能会或可能不会唤醒并完成其工作。 Java中的GC通常是不值得信任的。

第二个答案:有时是,有时没有,但不值得冒险。来自Elliote Rusty Harold's Java IO

  

并非所有流都需要是闭合字节数组输出流   例如,需要关闭。但是,与文件关联的流   完成后,应始终关闭网络连接。   例如,如果您打开文件进行书写而忽略它以何时关闭它   你通过了,然后其他进程可能被阻止阅读或   写到那个文件。

根据Harold的说法,输入或输出流也是如此。有一些例外(他注意到System.in),但一般来说,如果你在完成后没有关闭文件流,你就冒了风险。并在finally块中关闭它们,以确保即使抛出异常也会关闭它们。

答案 1 :(得分:6)

我曾经假设流最终会通过垃圾收集自动关闭,但轶事证据表明无法手动关闭它们会导致资源泄漏。你会想做这样的事情:

InputStream stream = null;

try {
  stream = new FileInputStream("bar.txt");
  Properties p = new Properties();
  p.load(stream);
}
catch(Exception e) {
  // error handling
}
finally {
  closeQuietly(stream);
}

closeQuietly()是Apache的commons-io库中IOUtils的方法。

答案 2 :(得分:5)

不,Java中没有析构函数。可能存在对该对象的其他引用,即使在对该对象的一个​​特定引用超出范围(或被修改)之后也是如此。如果该对象不再可访问,则该流可能会在稍后调用其终结器,这将关闭该流。

Properties.load很奇怪,它会关闭传递给它的流。编辑:Properties.loadFromXML是我似乎在考虑大约五年前的特殊方法。 (API doc应该先说而不是之后。)谢谢@tzimnoch。

答案 3 :(得分:3)

变量超出范围,因此被销毁。但在Java中,变量对象之间存在很大的区别,变量指向

仅当变量超出范围时,才会销毁指向的对象。该对象仅在Java运行时引擎决定它想要破坏任何范围内变量未指向的对象时才被销毁。

答案 4 :(得分:3)

简短的回答是“也许,但不要赌它!”。

实现FileInputStream的类堆栈中的某个地方是一个具有finalizer的类,它将在运行时有效地关闭流(并释放资源)。

问题在于无法保证终结器能够运行。引自JLS(第12.6节):

  

Java编程语言没有   指定终结者的时间   调用,除了说它会   发生在存储之前   对象被重用。

这使得流终结成为问题:

  1. 如果您的Stream对象永远不会变成垃圾,它将永远不会被最终确定。
  2. 如果您的Stream对象是终身对象,则可能需要很长时间才能进行垃圾回收和最终确定。
  3. 在执行终结器之前,在将对象标识为无法访问之后,JVM可能需要执行额外的GC周期。这肯定是JLS允许的!
  4. JVM永远不会执行终结器在技术上是合法的,只要它永远不会重复使用终结器的对象存储。 (我不知道任何生产质量的JVM采用这条线,但你永远不知道......)