Ответ 1
javadoc довольно явный:
Закрытие StringWriter не влияет.
И быстрый взгляд на код подтверждает это:
public void close() throws IOException {
}
Я понимаю, что в java GC в конечном итоге очистит объекты, но я спрашиваю, не является ли плохая практика не закрывать строковый писатель, в настоящее время я делаю это:
private static String processTemplate(final Template template, final Map root) {
StringWriter writer = new StringWriter();
try {
template.process(root, writer);
} catch (TemplateException e) {
logger.error(e.getMessage());
} catch (IOException e) {
logger.error(e.getMessage());
}
finally {
}
return writer.toString();
}
Должен ли я закрывать запись и создавать новую строку следующим образом:
String result = "";
...
finally {
result = writer.toString();
writer.close();
}
Это лучше сделать?
javadoc довольно явный:
Закрытие StringWriter не влияет.
И быстрый взгляд на код подтверждает это:
public void close() throws IOException {
}
Он не содержит никакого ресурса без памяти. Это будет сбор мусора, как и все остальное. Вероятность close() существует только потому, что другие объекты-хранители хранят ресурсы, которые необходимо очистить, а close() необходим для насыщения интерфейса.
В конце метода нет ссылки на writer
, поэтому он будет освобожден GC.
Нет, не закрытие StringWriter
не приведет к утечке: как отмечено, StringWriter#close()
- это nop, а у писателя есть только память, а не внешние ресурсы, поэтому они будут собраны, когда сборщик будет собран. (Явно, он содержит ссылки на объекты в частных полях, которые не выходят из объекта, а конкретно StringBuffer
, поэтому никаких внешних ссылок.)
Кроме того, вы обычно не должны закрывать StringWriter
, потому что он добавляет шаблон к вашему коду, скрывая основную логику, как мы увидим. Однако, чтобы успокоить читателей, что вы осторожны и делаете это намеренно, я бы рекомендовал прокомментировать этот факт:
// Don't need to close StringWriter, since no external resource.
Writer writer = new StringWriter();
// Do something with writer.
Если вы хотите закрыть автора, наиболее элегантным является использование try-with-resources, который автоматически вызовет close()
когда вы выходите из тела блока try:
try (Writer writer = new StringWriter()) {
// Do something with writer.
return writer.toString();
}
Однако, поскольку Writer # close() throws IOException
, вашему методу теперь нужно также бросить IOException
, хотя это никогда происходит, или вам нужно поймать его, чтобы доказать компилятору, что он обрабатывается. Это очень важно:
Writer writer = new StringWriter();
try {
// Do something with writer, which may or may not throw IOException.
return writer.toString();
} finally {
try {
writer.close();
} catch (IOException e) {
throw new AssertionError("StringWriter#close() should not throw IOException", e);
}
}
Этот уровень шаблона необходим, потому что вы не можете просто поместить catch в общий блок try, так как иначе вы можете случайно усвоить IOException
, выброшенную телом вашего кода. Даже если в настоящее время их нет, некоторые могут быть добавлены в будущем, и вы должны быть предупреждены об этом компилятором. AssertionError
документирует текущее поведение StringWriter#close()
, которое может потенциально измениться в будущей версии, хотя это крайне маловероятно; он также маскирует любое исключение, которое может возникнуть в теле try (опять же, это никогда не должно происходить на практике). Это слишком много шаблонов и сложности, и вам явно будет лучше не пропускать close()
и комментировать почему.
Тонкая точка состоит в том, что не только Writer#close()
бросает IOException
, но также StringWriter#close()
, поэтому вы можете Исключить исключение, сделав переменную a StringWriter
вместо Writer
. Это отличается от StringReader, который переопределяет метод close()
и указывает, что он не генерирует исключения! См. мой ответ на Должен ли я закрыть StringReader?. Это может выглядеть неправильно - почему у вас есть метод, который ничего не делает, но может вызывать исключение? - но, по-видимому, для прямой совместимости, чтобы оставить возможность бросать IOException
в ближайшем будущем, поскольку это проблема для писателей в целом. (Это также может быть просто ошибкой.)
Подводя итог: отлично, чтобы не закрыть StringWriter
, но причина не делать обычную правильную вещь, а именно try-with-resources, заключается только в том, что close()
заявляет, что она выдает исключение, Фактически бросать на практике, и для этого достаточно много шаблонов. В любом другом случае лучше просто использовать условно правильный шаблон управления ресурсами и предотвратить проблемы и поцарапать голову.