попробуйте-с-ресурсами, где обернуть поток с помощью 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 ресурсов позвонил в обратном порядке их создания.