Reputation: 3
I am learning Java and have a question that I can't seem to find the answer to anywhere. Or maybe I just lack the proper keywords to google it, as I'm relatively new to Java.
I'm trying to create a class for deep-copying using Serialization.
public class SerialDeepCopier<T extends Serializable> {
public T deepCopy(T origin) throws Exception{
ByteArrayOutputStream writeBuffer = new ByteArrayOutputStream();
ObjectOutputStream oStream = new ObjectOutputStream(writeBuffer);
oStream.writeObject(origin);
ByteArrayInputStream readBuffer = new ByteArrayInputStream(writeBuffer.toByteArray());
ObjectInputStream iStream = new ObjectInputStream(readBuffer);
T returnValue = (T) iStream.readObject();
/*
CLOSE THE STREAMS
*/
writeBuffer.close();
oStream.close();
readBuffer.close();
iStream.close();
return returnValue;
}
}
I'm aware that it's good practice to always close streams after the program is done using them, which begs this question because not instantiating the streams into an object also works:
ByteArrayOutputStream writeBuffer = new ByteArrayOutputStream();
new ObjectOutputStream(writeBuffer).writeObject(origin);
When I wrote it like that, I obviously can't manually call the close()
method to close the stream (or at least I don't know how to) as there is no object to do it from.
So, if I instantiate a stream without assigning it to an object, how am I supposed to close it?
return
?writeObject(origin)
task?Upvotes: 0
Views: 171
Reputation: 718718
No. They do not close themselves on return.
- Does the GC just automagically closes it?
Eventually. If the GC detects that a stream is unreachable it will trigger its closure via finalization or a cleaner.
- Does it automatically close on return?
No. Until the GC runs, the JVM doesn't know if the stream is still reachable. A reference to the stream could have been squirreled away in (say) a static
variable by various of the constructors or methods called in your deepCopy
method.
- Or does it just immediately closes after instantiation and completing it's
writeObject(origin)
task.
No. The streams objects themselves have no way of knowing that the writeObject
call is the last task that will be performed on / with then.
So is it just generally a bad idea to do this:
new ObjectOutputStream(writeBuffer).writeObject(origin);
?
It depends what the underlying streams are.
In this case, the streams are reading and writing in-memory byte arrays. So in this case it doesn't really matter that they are not garbage collected quickly.
On the other hand, if the streams were connected to external resources (e.g. files, pipes, sockets, etc) then it can matter. For instance on Windows you may be holding a lock on a file that prevents other applications opening it. Or on Linux, you are tying down file descriptors ... which are a relatively scarce resource.
Having said that, it is a good idea to close streams anyway:
close()
to complete the stream. A flush()
is not always sufficient. (An example is an output stream that does compression or encryption.)And the simplest reliable way to do it is to use try with resources.
Upvotes: 3