Proper way to close an AutoCloseable
The correct way to use an AutoCloseable
instance is with a try
-with-resources block, so the resource is reliably closed even if an exception is thrown.
Like this:
try (OutputStream stream = new ...) {
... // use the resource
} catch (IOException e) {
... // exception handling code
}
You can also control multiple resources using one block (rather than nested blocks):
try (
OutputStream out1 = ...;
OutputStream out2 = ...;
InputStream in1 = ...;
InputStream in2 = ...;
) {
...
}
Don't use a try
...finally
block: that will misbehave for some edge cases (the cases that require a suppressed exception).
Don't use a shutdown-hook: resources are rarely truely gloabl, and that approach will be prone to race hazards. try
-with-resources is the recommended manner of properly closing all AutoCloseable
resources: the two were introduced to Java at the same time so they can work together.
Doing this implicitly helps implement the (recommended) rule that only the code responsible for creating or opening something is responsible for disposing or closing it: if a method is passed an OutputStream
, it should never close()
it. It should instead rely on the caller closing it. If none of your methods explicitly call close()
, your code is guaranteed never to throw an exception (such as a "Socket closed" java.net.SocketException
) because it attempts to use a resource that has been closed.
Doing this ensures that the resource is closed precisely once. Beware that in general it is unsafe to close an AutoCloseable
more than once: the close()
operation is not guaranteed to be idempotent.
Order of execution of Closeable and AutoCloseable close() methods
try-with-resources closes the resources in the opposite order to the order they were declared in. So that code:
- Prints
T
- The try-with-resources statement attempts to close
r2
- That throws an exception
- The try-with-resources statement successfully closes
r1
, which outputs1
- The exception block is run (for the exception from
r2
) and outputsIOE
- The finally block is run, outputting
F
It's worth reading through the try-with-resources part of the JLS, which includes code examples of an unravelled try-with-resources statement (e.g., the equivalent code with just try
/catch
/finally
). From that section:
Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources. Such an exception is suppressed if an exception was thrown previously by an initializer, the try block, or the closing of a resource.
AutoCloseable close() method exception not getting suppressed
I think you have to read the article about try-with-resource again.
Exceptions are only suppressed if there are more than one. Also an order is specified when and which exceptions are suppressed like in this example:
public class Test {
public static void main(String... args) {
try (ExceptionResource test = new ExceptionResource()) {
test.work();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ExceptionResource implements AutoCloseable {
public void work() throws Exception {
throw new Exception("Thrown in 'run'");
}
@Override
public void close() throws Exception {
throw new Exception("Thrown in 'close'");
}
}
Outcome:
java.lang.Exception: Thrown in 'run'
at test.ExceptionResource.work(Test.java:16)
at test.Test.main(Test.java:6)
Suppressed: java.lang.Exception: Thrown in 'close'
at test.ExceptionResource.close(Test.java:21)
at test.Test.main(Test.java:7)
implements Closeable or implements AutoCloseable
It seems to me that you are not very familiar with interfaces. In the code you have posted, you don't need to implement AutoCloseable
.
You only have to (or should) implement Closeable
or AutoCloseable
if you are about to implement your own PrintWriter
, which handles files or any other resources which needs to be closed.
In your implementation, it is enough to call pw.close()
. You should do this in a finally block:
PrintWriter pw = null;
try {
File file = new File("C:\\test.txt");
pw = new PrintWriter(file);
} catch (IOException e) {
System.out.println("bad things happen");
} finally {
if (pw != null) {
try {
pw.close();
} catch (IOException e) {
}
}
}
The code above is Java 6 related. In Java 7 this can be done more elegantly (see this answer).
How should a closed resource behave in java?
What is the canonical Java way?
First, let's look at the javadoc of the 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.
So the answer to your options is "none of the above" for the close()
method. You don't throw an exception, and you don't let exceptions through from the closed resource. If it has been closed, the call must be a NOOP.
Now, let's have a look at some of the Closeable
classes:
FileInputStream.read()
Throws
IOException
if an I/O error occurs.That includes "file closed".
That goes for all the InputStream/OutputStream/Reader/Writer I/O classes.
FileSystem.close()
After a file system is closed then all subsequent access to the file system, either by methods defined by this class or on objects associated with this file system, throw
ClosedFileSystemException
. If the file system is already closed then invoking this method has no effect.Formatter.close()
Attempting to invoke any methods except
ioException()
in this formatter after it has been closed will result in aFormatterClosedException
.URLClassLoader.findClass(name)
Throws
ClassNotFoundException
if the class could not be found, or if the loader is closed.
Conclusion: All the methods (except close()
) throw exceptions, though not IllegalStateException
.
You can of course use IllegalStateException
if you want.
How do I close a thread local autocloseable used in parallel stream?
ThreadLocal are closed after the thread using them dies. If you want control over this you need to use a map instead.
// do our own thread local resources which close when we want.
Map<Thread, Resource> threadLocalMap = new ConcurrentHashMap<>();
fj.submit(
() -> myStream.parallel().forEach(e -> {
Resource r = threadLocalMap.computeIfAbsent(Thread.currentThread(), t -> new Resource();
// use the thread local autocloseable here,
})
// later once all the tasks have finished.
// close all the thread local resources when the parallel processing is done
threadLocalMap.values().forEach(Utils::closeQuietly);
It's common to have a method which closes resources without throwing an exception. Chronicle has one but so do many other libraries.
public static void closeQuietly(Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException ioe) {
// ignore or trace log it
}
}
}
Most likely you have a method do this in your project already
https://www.google.co.uk/search?q=public+static+void+closequietly+Closeable
Autocloseable class doesn't invoke default close method
Because you're not using try-with-resources
. AutoCloseable
is only invoked with that, not with regular try/catch
statements.
The correct pattern would be
try(Resource first = new Resource(1); Resource second = new Resource(2)) {
// .. whatever
}
Related Topics
Swing's Keylistener and Multiple Keys Pressed at the Same Time
Resizing Icon to Fit on Jbutton in Java
Problem with "Scopes" of Variables in Try Catch Blocks in Java
Highlighting Strings in Javafx Textarea
Jersey 415 Unsupported Media Type
Providing Input/Subcommands to Command Executed Over Ssh with Jsch
Jtable Model Listener Detects Inserted Rows Too Soon (Before They Are Drawn)
Selenium Switch Focus to Tab, Which Opened After Clicking Link
Differencebetween @Inject and @Autowired in Spring Framework? Which One to Use Under What Condition
Run a Single Test Method with Maven
Building Executable Jar with Maven
Should I Declare Jackson's Objectmapper as a Static Field
Fastest Way to Iterate Over All the Chars in a String
Can a Constructor in Java Be Private