views:

182

answers:

5

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.

+4  A: 

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.

Tom Hawtin - tackline
There are no destructors, but there are finalizers. And finalizers for majority of InputStream / OuputStream classes from java.io DO close the stream.
ChssPly76
@ChssPly76: Right, but there is no guarantee *whatsoever* about when, or even whether, finalizers will get called. None.
T.J. Crowder
+3  A: 

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.

Justice
+6  A: 

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.

rtperson
+3  A: 

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
+1  A: 

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 never becomes garbage, it will never be finalized.
  2. JVM may perform more than one GC cycle before the finalizer is executed. It is certainly allowed to by the JLS!
  3. 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