12

Does InputStreams and OutputStreams in Java close() on destruction? I fully understand that this may be bad form (esp in C and C++ world), but I'm curious.

Also, suppose I have the following code:

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

Does the nameless FileInputStream goes out of scope after p.load(), and therefore get destroyed, kinda like C++ scoping rules? I tried searching for anonymous variable scope for java on Google, but that didn't turn up what I thought it would be.

Thanks.

Calyth
  • 1,673
  • 3
  • 16
  • 26
  • Note that the `try` with resources in Java 7 or higher would make fixing this issue a relatively simple operation (just requiring one additional variable assignment and of course the `try` itself). Also note tht above code would generate a warning (about the missing close) in my Eclipse environment. – Maarten Bodewes Feb 11 '16 at 10:14

5 Answers5

19

First answer: there's no such thing as "destruction" (in the C++ sense) in Java. There's only the Garbage Collector, which may or may not wake up and do its job when it sees an object that's ready to be collected. GC in Java is generally untrustworthy.

Second answer: sometimes yes, sometimes no, but not worth taking a risk over. From Elliote Rusty Harold's Java IO:

Not all streams need to be closed—byte array output streams do not need to be closed, for example. However, streams associated with files and network connections should always be closed when you're done with them. For example, if you open a file for writing and neglect to close it when you're through, then other processes may be blocked from reading or writing to that file.

According to Harold, the same goes for Input or Output streams. There are some exceptions (he notes System.in), but in general, you're taking a risk if you don't close file streams when you're done. And close them in a finally block, to make sure they get closed even if an exception is thrown.

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
rtperson
  • 11,632
  • 4
  • 29
  • 36
6

I used to assume streams would be closed automatically eventually via garbage collection, but anecdotal evidence indicates that failure to manually close them results in a resource leak. You will want to do something like this instead:

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() is a method on IOUtils in Apache's commons-io library.

SingleShot
  • 18,821
  • 13
  • 71
  • 101
5

No, there are no destructors in Java. There may be other references to the object, even after one particular reference to it goes out of scope (or is modified). If the object is no longer reachable, the stream may have its finaliser called sometime later which will close the stream.

Properties.load is peculiar in the it closes the stream passed to it. Edit: Properties.loadFromXML is the special method I appear to have been thinking about five or so years ago. (API doc should probably say before rather than after.) Thank you @tzimnoch.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • There are no destructors, but there are finalizers. And finalizers for majority of InputStream / OuputStream classes from java.io DO close the stream. – ChssPly76 Oct 05 '09 at 21:06
  • 5
    @ChssPly76: Right, but there is no guarantee *whatsoever* about when, or even whether, finalizers will get called. None. – T.J. Crowder Oct 05 '09 at 21:08
  • 1
    https://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load(java.io.InputStream) "The specified stream remains open after this method returns." – tzimnoch Mar 29 '16 at 16:32
3

The variable goes out of scope and is therefore destroyed. But in Java, there is a very big distinction between a variable and the object which the variable points to.

The object pointed to is not destroyed merely when the variable goes out of scope. The object is only destroyed when the Java runtime engine decides it feels like getting around to destroying objects that are not pointed to by any in-scope variables.

yfeldblum
  • 65,165
  • 12
  • 129
  • 169
3

The short answer is "maybe, but don't bet on it!".

Somewhere in the stack of classes that implement FileInputStream is a class that has a finalizer that will effectively close the stream (and release the resource) when it is run.

The problem is that there is no guarantee that the finalizer will ever run. Quoting from the JLS (section 12.6):

The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.

This makes stream finalization problematic:

  1. If your Stream object never becomes garbage, it will never be finalized.
  2. If your Stream object is tenured, it may take a long time before it is garbage collected and finalized.
  3. The JVM may need to perform an extra GC cycle after the object is identified as unreachable before the finalizer is executed. This is certainly allowed by the JLS!
  4. It is technically legal for a JVM to never, ever to execute finalizers, provided that it never reuses the store of objects with finalizers. (I'm not aware of any production quality JVMs that take this line, but you never know ...)
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I would think that if the JVM got low in resources it would finalize closed file objects. (Not to condone not cleaning up after yourself.) – mike jones May 15 '14 at 14:39
  • You might think that ... but AFAIK, running out of file descriptors does not trigger a GC run that would detect that other stream objects are (hypothetically) now finalizable. – Stephen C May 15 '14 at 14:53
  • @mike jones: no, it’s not the case. This can be practically proven. Getting low on memory can trigger garbage collection (it’s even mandated to try its best before throwing an `OutOfMemoryError`), but gc is *not* identical to finalization. Garbage collection will cause objects with finalizers to be *enqueued* for later finalization, but it’s completely undefined when finalization will happen. So while running out of file descriptors (or any other non-memory resource) does not trigger gc anyway (as Stephen already pointed out), even if gc is triggered, it doesn’t force finalization. – Holger Sep 20 '16 at 10:53