8

If I want to automatically close a resource passed as an argument, is there a more elegant solution than this?

void doSomething(OutputStream out) {

  try (OutputStream closeable = out) {
    // do something with the OutputStream
  }
}

Ideally, I'd like to have this resource closed automatically, without declaring another variable closeable that refers to the same object as out.

Aside

I realise that closing out within doSomething is considered a bad practice

Dónal
  • 185,044
  • 174
  • 569
  • 824
  • 4
    I think the `doSomething` method should not close the input stream itselft. The caller should take care of it. – Mạnh Quyết Nguyễn Aug 14 '18 at 09:19
  • I believe java 9 allows that (the `out` variable is effectively final). But there's a risk for method parameters, I think. – ernest_k Aug 14 '18 at 09:21
  • 1
    @oleg.cherednik It does implement `AutoCloseable`, from the [Javadoc](https://docs.oracle.com/javase/10/docs/api/java/io/OutputStream.html): _"All Implemented Interfaces: Closeable, Flushable, AutoCloseable". It directly implements `Closeable` which extends `AutoCloseable`. – Mark Rotteveel Aug 14 '18 at 09:39
  • @MarkRotteveel I can see another picture in my sources. Probably it depends on JVM version. – Oleg Cherednik Aug 14 '18 at 09:40
  • @oleg.cherednik Only if you're using Java 6 or lower. `AutoCloseable` was introduced in Java 7. Or maybe you've overlooked that `Closeable` is a sub-interface of `AutoCloseable`). – Mark Rotteveel Aug 14 '18 at 09:41

3 Answers3

5

With Java 9 and higher, you can do

void doSomething(OutputStream out) {
  try (out) {
    // do something with the OutputStream
  }
}

This is only allowed if out is final or effectively final. See also the Java Language Specification version 10 14.20.3. try-with-resources.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • I'm using Java 8 at the moment, but good to know there's a more elegant solution in the next version – Dónal Aug 14 '18 at 09:55
  • @Dónal The only thing in Java 8 that would make your current code (as shown) shorter is replacing `OutputStream closeable` by `Closeable closeable`, but I think that is grasping at straws and makes the intent even less obvious. – Mark Rotteveel Aug 14 '18 at 10:16
3

I use Java 8 and it does not support Resource Reference. What about create universal method that accepts Closable and payload:

public static <T extends Closeable> void doAndClose(T out, Consumer<T> payload) throws Exception {
    try {
        payload.accept(out);
    } finally {
        out.close();
    }
}

Client code could look like this:

OutputStream out = null;

doAndClose(out, os -> {
    // do something with the OutputStream
});

InputStream in = null;

doAndClose(in, is -> {
    // do something with the InputStream
});
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
  • Can you include an example how this would be applied (eg as a replacement in the `doSomething` method)? – Mark Rotteveel Aug 14 '18 at 10:18
  • This removes the potential confusion that might arise from 2 references to the closeable resource being accessible within the payload body. It should probably accept a `Consumer super T>`, though. – Hulk Aug 14 '18 at 10:57
-4
void doSomething(OutputStream out) {
  try {
    // do something with the OutputStream
  }
  finally {
    org.apache.commons.io.IOUtils.closeQuietly(out);
  }
}
M.F
  • 403
  • 2
  • 10
  • From the [JavaDocs of org.apache.commons.io.IOUtils.ArrayUtils.closeQuietly](https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html#closeQuietly-java.io.OutputStream-): "**Deprecated.** As of 2.6 removed without replacement. Please use the try-with-resources statement or handle suppressed exceptions manually." – Hulk Aug 14 '18 at 10:50