Закрытие Java InputStreams
У меня есть некоторые вопросы об использовании метода close() при использовании Java InputStreams. Из того, что я вижу и читаю от большинства разработчиков, вы всегда должны явно ссылаться на close() на InputStream, когда он больше не нужен. Но сегодня я искал использование файла свойств Java, и каждый пример, который я нашел, имеет что-то вроде этого:
Properties props = new Properties();
try {
props.load(new FileInputStream("message.properties"));
//omitted.
} catch (Exception ex) {}
В приведенном выше примере нет возможности явно вызвать функцию close(), потому что InputStream недоступен после его использования. Я видел много подобных применений InputStreams, хотя, похоже, это противоречит тому, что большинство людей говорит о явном закрытии. Я прочитал Oracle JavaDocs и не упоминает, закрывает ли метод Properties.load() InputStream. Мне интересно, является ли это вообще приемлемым или предпочтительнее сделать что-то большее, чем следующее:
Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
props.load(fis);
//omitted.
} catch (Exception ex) {
//omitted.
} finally {
try {
fis.close();
} catch (IOException ioex) {
//omitted.
}
}
Какой способ лучше и/или эффективнее? Или это действительно имеет значение?
Ответы
Ответ 1
Примеры в "Свойства" закрывают FileInputStream
явно после загрузки, поэтому я считаю безопасным предположить, что метод load
не несет ответственности за это, вы.
// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();
Для справки я проверил Apache Harmony Properties, и он не закрывает поток при загрузке.
Ответ 2
Класс Properties переносит входной поток в LineReader для чтения файла свойств. Поскольку вы предоставляете входной поток, это ваша ответственность за его закрытие.
Второй пример - лучший способ обработки потока на сегодняшний день, не полагайтесь на кого-то другого, чтобы закрыть его для вас.
Одним из улучшений, которые вы можете сделать, является использование IOUtils.closeQuietly()
http://commons.apache.org/io/api-1.2/org/apache/commons/io/IOUtils.html#closeQuietly(java.io.InputStream)
чтобы закрыть поток, например:
Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
props.load(fis);
//omitted.
} catch (Exception ex) {
//omitted.
} finally {
IOUtils.closeQuietly(fis);
}
Ответ 3
Я бы пошел с try-with-ресурсами (по крайней мере, для Java 7 +):
Properties props = new Properties();
try(InputStream fis = new FileInputStream("message.properties")) {
props.load(fis);
//omitted.
} catch (Exception ex) {
//omitted.
}
Вызов функции close() должен быть вызван автоматически при выходе из блока try.
Ответ 4
В документации не упоминается, что props.load
закрывает входной поток. Вы должны закрыть входной поток вручную в блоке finally, как вы предлагаете.
Это не нормально для функции, чтобы закрыть InputStream
. Это же соглашение применяется как к памяти на языках, не связанных с мусором: если возможно, тот, кто открывает поток, должен закрыть поток. В противном случае очень легко оставить поток открытым (вы думаете, что функция собирается закрыть его, но это не так или что-то...)
Ответ 5
Если вы используете Java 7+, вы можете использовать это:
try(InputStream is = new FileInputStream("message.properties")) {
// ...
}
Ответ 6
Похоже, что первый пример кода заканчивается использованием метода finalize в FileInputStream для фактического закрытия файла. Я бы сказал, что ваш второй пример лучше, хотя в обоих случаях файл закрывается.
Есть такие случаи, как потоки байтов, где close ничего не делает и может быть опущен, иначе я думаю, что лучше явно закрыть файл в блоке finally. Если вы откроете его, закройте его.
Существует книга на сайте Oracle под названием Производительность платформы Java, в которой обсуждаются финализаторы в приложении, в ней говорится:
Вы почти всегда лучше выполняете свою собственную очистку вместо того, чтобы полагаться на финализатор. Использование финализатора также может оставить за собой критические ресурсы, которые не будут восстановлены в течение неопределенного периода времени. Если вы планируете использовать финализатор для обеспечения своевременного освобождения важных ресурсов, вам может потребоваться пересмотреть.
Ответ 7
Позвольте мне добавить кое-что к другим людям.
Если вы можете импортировать Apache Commons IO, вы можете использовать всегда удобную AutoCloseInputStream
: вы завершаете свой InputStream
, а затем просто используете свой завернутый экземпляр, и он автоматически закрывается, как только когда конец ввода достигнут или когда поток явно закрыт, в зависимости от того, что наступит раньше.