You don't need to catch an exception if your variable has type StringReader
, instead of Reader
, since StringReader#close()
doesn't throw an exception: only Reader#close()
does. So you can use try-with-resources to automatically close the reader, without needing to have boilerplate to handle exceptions that won't occur. Reader#close()
throwing IOException
means subtypes can throw this type of exception, not that they must. This is one of the rare cases where you want to declare a variable with a subtype, not the supertype; see Use interface or type for variable definition in java? for more.
Thus, I'd suggest the following, which just requires one level of nesting, which is par for resources:
try (StringReader reader = new StringReader(string)) {
// Do something with reader.
}
However, there's little value in closing a StringReader
, since it doesn't hold an external resource (only Java-managed memory, not a file handle or native memory, say), so it's fine to omit it, though I'd recommend a comment stating why this is safe, since otherwise not closing a reader is surprising. As you note, close()
just nulls out the field, per JDK 8 source: StringReader.java:198. If you want to avoid the nesting and close, you could just write this:
// Don't need to close StringReader, since no external resource.
StringReader reader = new StringReader(string);
// Do something with reader.
...or (using more general type for variable):
// Don't need to close StringReader, since no external resource.
Reader reader = new StringReader(string);
// Do something with reader.
Normal try-with-resources works here because StringReader#close()
overrides Reader#close()
and mercifully states that it does not throw IOException
.
Beware that this is not the case for StringWriter: StringWriter#close()
does declare that it throws IOException
, despite being a nop! This is presumably for forward compatibility, so it could throw an exception in a future implementation, though this is unlikely. See my answer to
Will not closing a stringwriter cause a leak?.
In such a case (if the method does not throw an exception, but the interface stated that it could), the tight way to write this, which you are presumably alluding to, is:
Reader reader = new StringReader(string);
try {
// Do something with reader, which may or may not throw IOException.
} finally {
try {
reader.close();
} catch (IOException e) {
throw new AssertionError("StringReader#close() cannot throw IOException", e);
}
}
This level of boilerplate is necessary because you can't just put a catch on the overall try block, as otherwise you might accidentally swallow an IOException
thrown by the body of your code. Even if there isn't any currently, some might be added in future and you'd want to be warned of this by the compiler. Note also that the AssertionError
, which documents the current behavior, would also mask an exception thrown by the body of the try statement, though this should never occur. If this were the alternative, you'd clearly be better off omitting the close()
and commenting why.
This answer depends on the fact that you're creating the StringReader
yourself; of course if you receive a Reader
from somewhere else (as the return type of a factory, say), then you need to close it and handle the possible exception, since you don't know what resources it may hold, and it may throw an exception.
Reader
I was dealing with, I would definitely close it. – Cameroncameroon