Reputation: 31262
I saw this code and wondered why in.close()
was done in the finally block
. The main point of try-with resources
is that it closes
the resources
correct.
File file = new File(FILE_NAME);
FileInputStream in = null;
try (in = new FileInputStream(file)){
//do something
} catch (final FileNotFoundException e) {
log.log(Level.WARNING, "file not found, " + file.getAbsolutePath(), e);
} catch (final IOException e) {
log.log(Level.WARNING, "cannot access the file for reading", e);
} finally {
if (in != null){
try {
in.close();
} catch (final IOException e) {
log.log(Level.WARNING, "Attempt to close file failed.", e);
}
}
}
Will there be a situation where a file can be opened but cannot be closed using try-with-resources in Java?
Upvotes: 2
Views: 1131
Reputation: 3599
The finally
block in your example is redundant. The try-with-resources statement is basically doing the same (but is significantly less error prone!). As it is executed after the try-with-resources statement attempts to close the resources, the finally
block is essentially a noop (there may be the possibility of a second attempt to close a resource succeeding after the first fails - but if this is even possible, it is a negligible edge case and certainly non-deterministic).
Note that the catch
blocks in contrast are significant. The attempt to close resources will take place before a catch
block is activated, leading to the possibility that more than one exception occurs. This is solved by using suppressed exceptions. Therefore, if using the resource fails, there will nonetheless be an attempt to close it properly (which will often fail too) and catch
blocks will receive the first (most likely root) cause, instead of the exception thrown while closing hiding the first error.
For more informations see the official documentation!
Upvotes: 4
Reputation: 1849
Yes, this can happen. The method signature for close()
does throw an IOException
, so a good programmer should be prepared for this eventuality.
Often, the catch block will be moved outside the method, which makes handling it somewhat easier and cleaner looking. For example:
public static void main(String[] args)
{
try {
readFile(new File("MyFile.txt"));
} catch (IOException e) {
/* handle the exception */
}
}
private static void readFile(File file) throws IOException
{
FileInputStream in = null;
try {
in = new FileInputStream(file);
/* Read the file. THIS MIGHT FAIL! */
} finally {
if (in != null) /* Check this because new FileInputStream() could have failed */
in.close(); /* If this throws and exception, it will be handled by main() */
}
}
Upvotes: 1
Reputation: 38235
I would do a simple test with some removable storage (USB stick, for instance):
Just write a program that opens a FileInputStream
with a file from the USB stick and then prompts "Please remove the storage device", waits for an <Enter> and then tries in.close()
. I would bet some IOException
would be thrown.
Upvotes: 1
Reputation: 13833
This is not exclusive to files, it happens in general with I/O.
The Java API specs that the close() method of InputStream may launch an exception if "An I/O error occurs"
So yes, it can happen, that behaviour generates that funny (or not so funnty) try-catch-finally-try-catch blocks.
Upvotes: 1