Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

try-with-resources where to wrap stream with InputStreamReader?

Tags:

java

java-7

I may be overthinking this, but I just wrote the code:

try (InputStream in = ModelCodeGenerator.class.getClassLoader().getResourceAsStream("/model.java.txt"))
{
    modelTemplate = new SimpleTemplate(CharStreams.toString(new InputStreamReader(in, "ascii")));
}

Which means the InputStreamReader is never closed (but in this case we know its close method just closes the underlying InputStream.)

One could write it as:

try (InputStreamReader reader = new InputStreamReader(...))

But this seems worse. If InputStreamReader throws for some reason, the InputStream won't ever be closed, right? This is a common problem in C++ with constructors that call other constructors. Exceptions can cause memory/resource leaks.

Is there a best practice here?

like image 728
Eloff Avatar asked Jan 21 '15 18:01

Eloff


People also ask

Does try with resources close stream?

The Java try with resources construct, AKA Java try-with-resources, is an exception handling mechanism that can automatically close resources like a Java InputStream or a JDBC Connection when you are done with them. To do so, you must open and use the resource within a Java try-with-resources block.

Does InputStreamReader close underlying stream?

InputStreamReader will not close an interface. It will close the underlying data resource (like file descriptor) if it is. It will do nothing if close is override and empty in an implementation.

How do you use try with resources?

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.

What are the resources used in exception handling?

For try-with-resources, if an exception is thrown in a try block and in a try-with-resources statement, then the method returns the exception thrown in the try block. The exceptions thrown by try-with-resources are suppressed, i.e. we can say that try-with-resources block throws suppressed exceptions.


1 Answers

Which means the InputStreamReader is never closed

Eh? In your code it is... And it will certainly handle the .close() of your resource stream as well. See below for more details...

As @SotiriosDelimanolis mentions however you can declare more than one resource in the "resource block" of a try-with-resources statement.

You have another problem here: .getResourceAsStream() can return null; you may therefore have an NPE.

I'd do this if I were you:

final URL url = ModelCodeGenerator.class.getClassLoader()
    .getResource("/model.java.txt");

if (url == null)
    throw new IOException("resource not found");

try (
    final InputStream in = url.openStream();
    final Reader reader = new InputStreamReader(in, someCharsetOrDecoder);
) {
    // manipulate resources
}

There is a very important point to consider however...

Closeable does extend AutoCloseable, yes; in fact it only differs, "signature wise", by the exception thrown (IOException vs Exception). But there is a fundamental difference in behavior.

From the javadoc of AutoCloseable's .close() (emphasis mine):

Note that unlike the close method of Closeable, this close method is not required to be idempotent. In other words, calling this close method more than once may have some visible side effect, unlike Closeable.close which is required to have no effect if called more than once. However, implementers of this interface are strongly encouraged to make their close methods idempotent.

And indeed, the javadoc of Closeable is clear about this:

Closes this stream and releases any system resources associated with it. If the stream is already closed then invoking this method has no effect.

You have two very important points:

  • by contract, a Closeable also takes care of all resources associated with it; so, if you close a BufferedReader which wraps a Reader which wraps an InputStream, all three are closed;
  • should you call .close() more than once, there is no further side effect.

This also means, of course, that you can choose the paranoid option and keep a reference to all Closeable resources and close them all; beware however if you have AutoCloseable resources into the mix which are not Closeable!

like image 199
fge Avatar answered Oct 13 '22 01:10

fge