How to Close an Autocloseable

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:

  1. Prints T
  2. The try-with-resources statement attempts to close r2
  3. That throws an exception
  4. The try-with-resources statement successfully closes r1, which outputs 1
  5. The exception block is run (for the exception from r2) and outputs IOE
  6. 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 a FormatterClosedException.

  • 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



Leave a reply



Submit