Will try-with-resources call flush() implicitly?
If it does, in the following code snippet, bw.flush() can be safely removed?
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
bw.flush();
} catch (IOException ex) {
// handle ex
}
}
ps.
I don't see any description about it in official document:
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html
Closeable and AutoCloseable are general-purpose interfaces that do not know anything about flushing. So you can't find any information about it in their documentation - except some words about releasing resources.
A Writer on the other hand is a more specific-purpose abstract class that now knows something about flushing. Some excerpt of the documentation for the method Writer.close():
Closes the stream, flushing it first.
So - yes - when using a writer, a close will always also flush. This basically means that you have to consult the documentation of the concrete classes that you are using when trying to find out what closing really does.
The resources are automatically closed when using try-with-resource block. As part of this process it will also invoke flush automatically.
As mentioned in doc for close method of BufferedWriter:
Closes the stream, flushing it first. Once the stream has been closed,
further write() or flush() invocations will cause an IOException to be
thrown.
Quoting javadoc of BufferedWriter.close():
Closes the stream, flushing it first.
The minimum amount of code to be written in this case:
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))) {
bw.write("Test");
} catch (IOException e) {
// handle exception
}
Hence you don't need to call explicitly the flush method, as it will be called by the close method, as explained in the javadoc:
Closes the stream, flushing it first. Once the stream has been closed,
further write() or flush() invocations will cause an IOException to be
thrown. Closing a previously closed stream has no effect.
This behavior is inherited from the Writer class, hence besides BufferedWriter the same behavior is provided also by: CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter.
This behavior is not provided in the documentation of the tryWithResources or AutoCloseable as the behavior is specific to the given implementation of Writer. As Writerextends Closeable, it will call the close method when exiting the try {} block and the close method will first call
flush as already mentioned.
I really don't understand why other answers focus on the BufferedWriter not try-with-resources.
I, either, couldn't find any specification or mentions that the try-with-resources statements calls flush() on any objects of Flushable.
https://docs.oracle.com/javase/specs/jls/se13/html/jls-14.html#jls-14.20.3
Don't rely on any undocumented/unspecified behavior of vendor specific implementations.
try (OutputStream o = open()) {
//writeSome
o.flush(); // won't hurt!
}
From the Javdocs:
The try-with-resources statement is a try statement that declares one
or more resources. A resource is an object that must be closed after
the program is finished with it. The try-with-resources statement
ensures that each resource is closed at the end of the statement. Any
object that implements java.lang.AutoCloseable, which includes all
objects which implement java.io.Closeable, can be used as a
resource.
The BufferedWriter.close() explicitly stated that:
Closes the stream, flushing it first. Once the stream has been closed, further write() or flush() invocations will cause an IOException to be thrown. Closing a previously closed stream has no effect.
Related
I saw this example, and I didn't see the close() method invoked on the InputStream, so would prop.load() close the stream automatically? Or is there a bug in the example?
The Stream is not closed after Properties.load ()
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(new File("abc.properties"));
new Properties().load(in);
System.out.println(in.read());
}
The above code returns "-1" so the stream is not closed. Otherwise it should have thrown java.io.IOException: Stream Closed
Why do you ask when the javadoc of Properties.load(InputStream inStream) says this?
The specified stream remains open after this method returns.
It has been saying that since Java 6.
As EJP said in a comment: Don't rely on arbitrary Internet junk. Use the official Oracle Java documentation as your primary source of information.
The following try-with-resources will close the InputStream automatically (you can add catch and finally if needed):
try (InputStream is = new FileInputStream("properties.txt")) {
// is will be closed automatically
}
Any resource declared within a try block opening will be closed. Hence, the new construct shields you from having to pair try blocks with corresponding finally blocks that are dedicated to proper resource management.
Article by Oracle here: http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html.
In my API (Spring boot) I have an endpoint where users can upload multiple file at once. The endpoint takes as input a list of MultipartFile.
I wish not to directly pass this MultipartFile object to the service directly so I loop through each MultipartFile and create a simple map that stored the filename and its InputStream.
Like this:
for (MultipartFile file : files) {
try (InputStream is = multipartFile.getInputStream()) {
filesMap.put(file.getOriginalFilename(), is);
}
}
service.uploadFiles(filesMap)
My understanding for Java streams and streams closing is quite limited.
I thought that try-with-resources automatically closes the InputStream once the code reached the end of the try block.
In the above code when does exactly the the multipartFile.getInputStream() gets closed?
The fact that I'm storing the stream in a map will that cause a memory leak?
Stream closes right after execution reaches closing bracket of try block.
It is okay to store InputStream anywhere after you closed it.
But be aware of that you can't read anything from this stream after you closes it.
Thanks to comments
Also, be aware of that some streams have special behavior on close() and it always depends on Stream realization.
For example:
If you try to read from closed FileInputStream you will get
java.io.IOException: Stream Closed
If you try to read from closed ByteArrayInputStream it will be okay, because of it's special close() realization: public void close() throws IOException {}
When does exactly the multipartFile.getInputStream() gets closed?
try (InputStream is = multipartFile.getInputStream()) {
filesMap.put(file.getOriginalFilename(), is);
} // <-- here
The try-with-resources statement ensures that each resource is closed at the end of the statement.
The fact that I'm storing the stream in a map will that cause a memory leak?
No, your collection just keeps closed InputStreams and you won't be able to read from them (in addition, you will get IOException).
If I invoke a BufferedReader the following way:
Integer.parseInt(new BufferedReader(new InputStreamReader(System.in)).readLine());
Will the JVM know to automatically close it when not in use? If not, how do I go about closing it?
If you are using java 7 or greater and your code is in try catch resource block, then it is Auto closes.
If in below versions you have to close with close(). For that you have to change your current way of using and get the reference.
Don't chain them, declare and assign variables, then close it after the usage.
InputStreamReader isReader;
BufferedReader bfReader;
try {
isReader = new InputStreamReader(System.in);
bfReader = new BufferedReader(isReader).readLine();
} catch (Exception e) {
// handle as per the requirement.
} finally {
bfReader.close();
}
If you use java 7, then, if you defined withing the try clause, then those will auto closable. Check here for more details
The try-with-resources statement is a try statement that declares one
or more resources. A resource is as an object that must be closed
after the program is finished with it. The try-with-resources
statement ensures that each resource is closed at the end of the
statement. Any object that implements java.lang.AutoCloseable, which
includes all objects which implement java.io.Closeable, can be used as
a resource.
Today, when I was working on some kind of servlet which was writing some information to some file present on my hard disk, I was using the following code to perform the write operation
File f=new File("c:/users/dell/desktop/ja/MyLOgs.txt");
PrintWriter out=new PrintWriter(new FileWriter(f,true));
out.println("the name of the user is "+name+"\n");
out.println("the email of the user is "+ email+"\n");
out.close(); //**my question is about this statement**
When I was not using the statement, the servlet was compiling well, but it was not writing anything to the file, but when I included it, then the write operation was successfully performed. My questions are:
Why was the data not being written to the file when I was not including that statement (even my servlet was compiling without any errors)?
Up to which extent the close operation is considerable for the streams?
Calling close() causes all the data to be flushed. You have constructed a PrintWriter without enabling auto-flush (a second argument to one of the constructors), which would mean you would have to manually call flush(), which close() does for you.
Closing also frees up any system resources used by having the file open. Although the VM and Operating System will eventually close the file, it is good practice to close it when you are finished with it to save memory on the computer.
You may also which to put the close() inside a finally block to ensure it always gets called. Such as:
PrintWriter out = null;
try {
File f = new File("c:/users/dell/desktop/ja/MyLOgs.txt");
out = new PrintWriter(new FileWriter(f,true));
out.println("the name of the user is "+name+"\n");
out.println("the email of the user is "+ email+"\n");
} finally {
out.close();
}
See: PrintWriter
Sanchit also makes a good point about getting the Java 7 VM to automatically close your streams the moment you don't need them automatically.
When you close a PrintWriter, it will flush all of its data out to wherever you want the data to go. It doesn't automatically do this because if it did every time you wrote to something, it would be very inefficient as writing is not an easy process.
You could achieve the same effect with flush();, but you should always close streams - see here: http://www.javapractices.com/topic/TopicAction.do?Id=8 and here: http://docs.oracle.com/javase/tutorial/jndi/ldap/close.html. Always call close(); on streams when you are done using them. Additionally, to make sure it is always closed regardless of exceptions, you could do this:
try {
//do stuff
} finally {
outputStream.close():
}
It is because the PrintWriter buffers your data in order for not making I/O operations repeatedly for every write operation (which is very expensive). When you call close() the Buffer flushes into the file. You can also call flush() for forcing the data to be written without closing the stream.
Streams automatically flush their data before closing. So you can either manually flush the data every once in a while using out.flush(); or you can just close the stream once you are done with it. When the program ends, streams close and your data gets flushed, this is why most of the time people do not close their streams!
Using Java 7 you can do something like this below which will auto close your streams in the order you open them.
public static void main(String[] args) {
String name = "";
String email = "";
File f = new File("c:/users/dell/desktop/ja/MyLOgs.txt");
try (FileWriter fw = new FileWriter(f, true); PrintWriter out = new PrintWriter(fw);) {
out.println("the name of the user is " + name + "\n");
out.println("the email of the user is " + email + "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
PrintWriter buffers the data to be written so and will not write to disk until its buffer is full. Calling close() will ensure that any remaining data is flushed as well as closing the OutputStream.
close() statements typically appear in finally blocks.
Why the data was not being written to the file when I was not including that statement?
When the process terminates the unmanaged resources will be released. For InputStreams this is fine. For OutputStreams, you could lose an buffered data, so you should at least flush the stream before exiting the program.
I expected to find XMLStreamReader to be AutoCloseable in Java 7. However, that is not the case. Is there a technical reason why StAX reader/writer interfaces were not (or should not be) retrofitted to implement AutoCloseable ? They already have close methods, whose intent is not different from the close method of AutoCloseable.
If you look closer to the close() method of AutoCloseable :
Closes this resource, relinquishing any underlying resources. This method is invoked automatically on objects managed by the try-with-resources statement.
Or even Closeable close() method :
Closes this stream and releases any system resources associated with it. If the stream is already closed then invoking this method has no effect.
Whereas the close() method of XMLStreamReader says :
Frees any resources associated with this Reader. This method does not close the underlying input source.
Indeed the input source is managed by the Reader which implement the Closeable interface. So it's the reader that can be close in the try-with-ressource.
For example :
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = null;
try (FileReader fr = new FileReader("file.xml")) { //Will close the FileReader
reader = factory.createXMLStreamReader(fr);
reader.close();
}
catch (XMLStreamException ex) {
if(reader!=null)try {
reader.close();
} catch (XMLStreamException ex1) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex1);
}
}
There is no technical reason why they couldn't have made these things AutoCloseable. I figure it just comes down to laziness or insufficient time looking for methods called close().