Должен ли я закрыть StringReader? - PullRequest
18 голосов
/ 25 мая 2011

Я использую StringReader, чтобы превратить строку во что-то, что я могу загрузить на SFTP-сервер (он принимает поток).Есть ли смысл закрывать это StringReader впоследствии?Насколько я вижу в исходном коде, он просто устанавливает строку в null ...

Я мог бы просто сделать это, но так как метод close помечен как выбрасывающий IOException, и все, что у меня естьобернуть его в попытку, и код в конечном итоге выглядит гораздо ужаснее, чем, возможно, должно быть.

Ответы [ 5 ]

13 голосов
/ 25 мая 2011

Если вы знаете, что имеете дело с StringReader, который будете выбрасывать, я не вижу смысла закрывать его.Я не могу представить причину, по которой вы будете хранить ссылку на нее после того, как закроете ее, так что нет никакой реальной выгоды, если строка будет установлена ​​на null для сборки мусора.Если вы создаете метод, который принимает Reader, то имеет смысл закрыть его, поскольку вы не знаете базовый тип.

4 голосов
/ 25 мая 2011

Хотя это и не является обязательным, поскольку StringReader поддерживает только строку, так как в любом случае полезно всегда закрывать все читатели. Сегодня ваш код может использовать StringReader, но если вы измените его на другой Reader, который действительно должен быть закрыт, ваш код без закрытия будет неправильным, а ваш с закрытием будет в порядке.

3 голосов
/ 25 мая 2011

Это делает больше, чем это. Если я могу процитировать JavaDoc:

/**
 * Closes the stream and releases any system resources associated with
 * it. Once the stream has been closed, further read(),
 * ready(), mark(), or reset() invocations will throw an IOException.
 * Closing a previously closed stream has no effect.
 */

Так что да, вы должны закрыть этот читатель. Не ради ресурсов, а ради хорошего стиля и программистов, которые могут следовать за вами. Вы не знаете, куда этот экземпляр будет передан и что кто-то другой попытается сделать с ним. Когда-нибудь вы также можете изменить интерфейс и принять любую реализацию Reader, в этом случае вы можете иметь дело с Reader, который требует вызова close () для освобождения ресурсов.

Так что это хороший стиль, чтобы предотвратить дальнейшее (возможно, неправильное) использование этого экземпляра, как только вы закончите с ним. И поскольку это не повредит, это только предотвратит возможные ошибки в будущем.

Edit: Поскольку вы говорите, что ваш метод close () объявляет исключение, которое он может выдать, я бы сказал, что вам нужно для вызова close (), поскольку StringReader.close () не выдает исключение. Однако Reader.close () делает. Таким образом, вы уже разрешаете другие реализации Reader, и поэтому вы должны закрыть его, поскольку вы не можете знать, какие реализации Reader вы в конечном итоге получите. Если мы говорим о трех строках кода, которые никогда не покидают эту область, объявите вашу переменную StringReader и в любом случае вызовите close (в этом случае без обработки исключений).

0 голосов
/ 31 августа 2015

Вам не нужно перехватывать исключение, если ваша переменная имеет тип 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 откуда-то еще (например, в качестве возвращаемого типа фабрики), вам нужно закрыть его и обработать возможное исключение, так как вы не знаете, какие ресурсы оно может содержать, и ономожет выдать исключение.

0 голосов
/ 25 мая 2011

Если вы закроете поток и освободите любые системные ресурсы, связанные с ним.Как только поток будет закрыт, дальнейшие вызовы read (), ready (), mark () или reset () вызовут IOException.Закрытие ранее закрытого потока не имеет никакого эффекта.Указано: закрыть в интерфейсе Closeable Указано: закрыть в классе Reader

...