Вам не нужно перехватывать исключение, если ваша переменная имеет тип StringReader
вместо Reader
, поскольку StringReader#close()
не вызывает исключение:только Reader#close()
делает.Таким образом, вы можете использовать try-with-resources для автоматического закрытия считывателя, без необходимости иметь шаблон для обработки исключений, которые не произойдут.Reader#close()
throwing IOException
означает, что подтипы могут генерировать исключение этого типа, но не должны .Это один из редких случаев, когда вы хотите объявить переменную с подтипом, а не с супертипом;см. Использовать интерфейс или тип для определения переменной в java? для получения дополнительной информации.
Таким образом, я бы предложил следующее, для которого требуется только один уровень вложенности, равный для ресурсов:
try (StringReader reader = new StringReader(string)) {
// Do something with reader.
}
Однако нет смысла закрывать StringReader
, поскольку он не содержит внешнего ресурса (скажем, только управляемой Java памяти, а не дескриптора файла или собственной памяти), так что все в порядкечтобы пропустить это, хотя я бы порекомендовал комментарий, объясняющий, почему это безопасно, так как в противном случае не закрытие читателя вызывает удивление.Как вы заметили, close()
просто обнуляет поле для источника JDK 8: StringReader.java: 198 .Если вы хотите избежать вложения и закрытия, вы можете просто написать это:
// Don't need to close StringReader, since no external resource.
StringReader reader = new StringReader(string);
// Do something with reader.
... или (используя более общий тип для переменной):
// Don't need to close StringReader, since no external resource.
Reader reader = new StringReader(string);
// Do something with reader.
Normal try-with-resources работает здесь, потому что StringReader#close()
переопределяет Reader#close()
и, к счастью, заявляет, что он не выбрасывает IOException
.
Остерегайтесь, что это не случай для String Writer: StringWriter#close()
действительно объявляет, что выбрасывает IOException
, несмотря на то, что не nop!Это предположительно для прямой совместимости, поэтому может вызвать исключение в будущей реализации, хотя это маловероятно.См. мой ответ на Не приведет ли закрытие редактора строк к утечке? .
В таком случае (если метод не выдает исключение, но интерфейс заданчто это возможно), точный способ написать это, на что вы, вероятно, намекаете, таков:
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);
}
}
Этот уровень шаблона необходим, потому что вы не можете просто поставить подвох в общем блоке try, иначе вы можете случайно проглотить IOException
, брошенный телом вашего кода.Даже если в настоящее время их нет, некоторые из них могут быть добавлены в будущем, и вы хотите, чтобы компилятор предупреждал об этом.Также обратите внимание, что AssertionError
, который документирует текущее поведение, также будет маскировать исключение, выдаваемое телом оператора try, хотя это никогда не должно происходить.Если бы это был альтернативный вариант, вам бы лучше было опустить close()
и прокомментировать почему.
Этот ответ зависит от того факта, что вы создаете StringReader
самостоятельно;конечно, если вы получаете Reader
откуда-то еще (например, в качестве возвращаемого типа фабрики), вам нужно закрыть его и обработать возможное исключение, так как вы не знаете, какие ресурсы оно может содержать, и ономожет выдать исключение.