Вам не нужно перехватывать исключение, если ваша переменная имеет тип StringReader
вместо Reader
, поскольку StringReader#close()
не генерирует исключение: только Reader#close()
делает. Таким образом, вы можете использовать try-with-resources для автоматического закрытия читателю, без необходимости иметь шаблон для обработки исключений, которые не возникнут. Reader#close()
выбрасывание 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.
Здесь работает обычная попытка с ресурсами, потому что StringReader#close()
переопределяет Reader#close()
и милостиво заявляет, что не выдает IOException
.
Имейте в виду, что это не относится к StringWriter: 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
откуда-то еще (например, как возвращаемый тип фабрики), вам нужно закрыть его и обработать возможное исключение, поскольку вы не знаете, какие ресурсы он может содержать, и он может выдать исключение.
person
Nils von Barth
schedule
30.08.2015