Не приведет ли закрытие строки к утечке?
Я понимаю, что в 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();
}
Это лучше сделать?
4 ответа
Он не содержит никаких ресурсов без памяти. Это будет мусор, как и все остальное. Вероятность закрытия close() существует просто потому, что другие объекты записи действительно содержат ресурсы, которые необходимо очистить, а метод close() необходим для защиты интерфейса.
Нет, не закрывая 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() выбрасывает 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);
}
}
Этот уровень шаблонного уровня необходим, потому что вы не можете просто поставить блокировку на весь блок try, иначе вы можете случайно проглотить IOException
брошенный телом вашего кода. Даже если в настоящее время их нет, некоторые из них могут быть добавлены в будущем, и вы захотите, чтобы компилятор предупредил об этом. AssertionError
документирует текущее поведение StringWriter#close()
, который потенциально может измениться в будущем выпуске, хотя это крайне маловероятно; он также маскирует любое исключение, которое может возникнуть в теле попытки (опять же, это никогда не должно происходить на практике). Это слишком много шаблонного и сложного, и вам, безусловно, будет лучше, если вы пропустите close()
и комментируя почему.
Тонкий момент заключается в том, что не только делает Writer#close()
бросить IOException
но так же StringWriter#close()
, поэтому вы не можете устранить исключение, сделав переменнуюStringWriter
вместоWriter
, Это отличается от String Reader, который переопределяетclose()
метод и указывает, что онне выдает исключение! См. Мой ответ на вопрос " Должен ли я закрыть StringReader?, Это может выглядеть неправильно - зачем вам метод, который ничего не делает, но может вызвать исключение? - но предположительно для прямой совместимости, чтобы оставить открытой возможность броска IOException
на закрытие в будущем, так как это проблема для писателей в целом. (Это также может быть просто ошибкой.)
Подводя итог: это нормально, чтобы не закрыть StringWriter
Но причина, по которой мы не делаем обычные правильные вещи, а именно: попробуй с ресурсами, заключается просто в том, что close()
заявляет, что он выдает исключение, которое он на самом деле не выдает на практике, и обработка этого точно - много шаблонного. В любом другом случае лучше просто использовать общепринятый правильный шаблон управления ресурсами и предотвратить проблемы и царапины на голове.
В конце метода нет ссылки на writer
поэтому он будет освобожден GC.