попробуйте-с-ресурсами, где обернуть поток с помощью InputStreamReader?
возможно, я слишком много думаю, но я только что написал код:
try (InputStream in = ModelCodeGenerator.class.getClassLoader().getResourceAsStream("/model.java.txt"))
{
modelTemplate = new SimpleTemplate(CharStreams.toString(new InputStreamReader(in, "ascii")));
}
что означает, что InputStreamReader никогда не закрывается (но в этом случае мы знаем, что его метод close просто закрывает базовый InputStream.)
можно написать так:
try (InputStreamReader reader = new InputStreamReader(...))
но это кажется еще хуже. Если InputStreamReader бросает по какой-то причине, InputStream никогда не будет закрыт, верно? Это общая проблема в C++ с конструкторами, которые вызывают другие конструкторы. Исключения может вызвать утечку памяти / ресурсов.
есть ли лучшая практика здесь?
2 ответов
что означает, что InputStreamReader никогда не закрывается
Ась? В твоем коде так и есть... И он, безусловно, справится .также закройте () вашего потока ресурсов. Подробнее см. ниже...
как @ SotiriosDelimanolis упоминает однако вы можете объявить несколько ресурсов в "блоке ресурсов" инструкции try-with-resources.
у вас есть еще одна проблема здесь:.getResourceAsStream() может возвращать null; вы можете поэтому имейте NPE.
на вашем месте я бы сделал это:
final URL url = ModelCodeGenerator.class.getClassLoader()
.getResource("/model.java.txt");
if (url == null)
throw new IOException("resource not found");
try (
final InputStream in = url.openStream();
final Reader reader = new InputStreamReader(in, someCharsetOrDecoder);
) {
// manipulate resources
}
есть очень важный момент, чтобы рассмотреть...
Closeable не распространяется AutoCloseable, Да; на самом деле он только отличается, "подпись мудрая", исключением (IOException vs Exception). Но есть фундаментальное различие в поведение.
из javadoc AutoCloseable ' s .close() (выделено мной):
обратите внимание, что в отличие от метода close Closeable этот метод close не обязательно должен быть идемпотентным. Другими словами, вызов этого метода close более одного раза может иметь видимый побочный эффект, в отличие от Closeable.закрыть, который не должен иметь никакого эффекта, если вызывается более одного раза. Однако разработчикам этого интерфейса настоятельно рекомендуется сделать свои методы close идемпотентными.
и действительно, javadoc Closeable понятно это:
закрывает этот поток и освобождает все связанные с ним системные ресурсы. Если поток уже закрыт, вызов этого метода не имеет никакого эффекта.
у вас есть два очень важных момента:
- по контракту, a
Closeableтакже заботится обо всех ресурсах, связанных с ним; поэтому, если вы закроетеBufferedReader, который обертываетReader, который оборачиваетсяInputStream, все три закрыты; - если вы называете
.close()более чем один раз, нет никаких побочных эффектов.
это также означает, конечно, что вы можете выбрать вариант paranoid и сохранить ссылку на все Closeable ресурсы и закройте их все; остерегайтесь, однако, если у вас есть AutoCloseable ресурсы в микс, которые не являются Closeable!
но это кажется еще хуже. Если
InputStreamReaderбросает по какой-то причинеInputStreamникогда не будет закрыт, верно?
это верно (хотя вряд ли,InputStreamReader конструктор не очень много делает).
на try-with-resources можно объявить столько ресурсов, сколько вы хотите. Объявите один для обернутого ресурса, а другой для InputStreamReader.
try (InputStream in = ModelCodeGenerator.class
.getClassLoader()
.getResourceAsStream("/model.java.txt");
InputStreamReader reader = new InputStreamReader(in)) {...}
отметим, что getResourceAsStream потенциально может вернуться null, который причина InputStreamReader конструктор кинуть NullPointerException. Если вы хотите справиться с этим по-другому, адаптируйте, как вы получаете ресурс, который должен быть обернут.
учебник, связанный выше, представляет этот пример
try (
java.util.zip.ZipFile zf =
new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer =
java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
с объяснением
в этом примере оператор try-with-resources содержит два объявления, разделенные точкой с запятой:
ZipFileиBufferedWriter. Когда блок кода, который непосредственно следует за ним завершает, обычно или из-за исключения, закрытие методыBufferedWriterиZipFileобъекты автоматически называют в таком порядке. Обратите внимание, что методы close ресурсов позвонил в обратном порядке их создания.