Закрытие входных потоков в Java
У меня есть следующий фрагмент кода в блоке try/catch
InputStream inputstream = conn.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
Мой вопрос в том, что когда мне нужно закрыть эти потоки в блоке finally, мне нужно закрыть все 3 потока или просто закрыть befferedreader закроет все остальные потоки?
Ответы
Ответ 1
По соглашению потоки-обтекатели (которые обертывают существующие потоки) закрывают нижележащий поток, когда они закрыты, поэтому нужно только закрыть bufferedreader
в вашем примере. Кроме того, обычно безопасно закрывать уже закрытый поток, поэтому закрытие всех трех потоков не повредит.
Ответ 2
Обычно нормально закрывать самый внешний поток, потому что по соглашению он должен запускать закрытие в базовых потоках.
Таким образом, обычно код выглядит следующим образом:
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
...
in.close(); // when you care about Exception-Handling in case when closing fails
}
finally {
IOUtils.closeQuietly(in); // ensure closing; Apache Commons IO
}
Тем не менее могут быть редкие случаи, когда базовый конструктор потока создает исключение, когда поток уже открыт. В этом случае вышеуказанный код не будет закрывать базовый поток, потому что внешний конструктор никогда не вызывался, а in
- null. Таким образом, блок finally не закрывает ничего, оставляя открытый поток.
Начиная с Java 7 вы можете сделать это:
try (OutputStream out1 = new ...; OutputStream out2 = new ...) {
...
out1.close(); //if you want Exceptions-Handling; otherwise skip this
out2.close(); //if you want Exceptions-Handling; otherwise skip this
} // out1 and out2 are auto-closed when leaving this block
В большинстве случаев вы не хотите, чтобы Exception-Handling возникал при закрытии, поэтому пропустите эти явные вызовы close().
Edit
Здесь приведен код для неверующих, где существенным является использование этого шаблона. Вы также можете прочитать Apache Commons IOUtils javadoc о методе closeQuietly().
OutputStream out1 = null;
OutputStream out2 = null;
try {
out1 = new ...;
out2 = new ...;
...
out1.close(); // can be skipped if we do not care about exception-handling while closing
out2.close(); // can be skipped if we ...
}
finally {
/*
* I've some custom methods in my projects overloading these
* closeQuietly() methods with a 2nd param taking a logger instance,
* because usually I do not want to react on Exceptions during close
* but want to see it in the logs when it happened.
*/
IOUtils.closeQuietly(out1);
IOUtils.closeQuietly(out2);
}
Использование @Tom "advice" оставит out1
открытым, когда создание out2
вызывает исключение. Этот совет от кого-то говорит о It a continual source of errors for obvious reasons.
Ну, я могу быть слепым, но это не очевидно для меня. Моя модель идиот-безопасна в каждом случае использования, о котором я могу думать, в то время как шаблон Tom подвержен ошибкам.
Ответ 3
Замыкание самого внешнего достаточно (т.е. BufferedReader
). Читая исходный код BufferedReader, мы видим, что он закрывает внутренний Reader
, когда вызывается его собственный метод закрытия:
513 public void close() throws IOException {
514 synchronized (lock) {
515 if (in == null)
516 return;
517 in.close();
518 in = null;
519 cb = null;
520 }
521 }
522 }
Ответ 4
Как правило, вы должны закрыть все в обратном порядке, чтобы вы их открыли.
Ответ 5
Я закрыл бы все из них в обратном порядке, из которого вы их открыли, как если бы при их открытии выталкивали читателя в стек, а закрытие выталкивало читателя из стека.
В конце концов, после закрытия всего, "стек считывателя" должен быть пустым.
Ответ 6
Вам нужно только закрыть реальный ресурс. Вы должны закрыть ресурс, даже если создание декораторов не удастся. Для вывода вы должны очистить самый декоративный объект в счастливом случае.
Некоторые осложнения:
- Иногда декораторы представляют собой разные ресурсы (некоторые реализации сжатия используют кучу C).
- Закрытие декораторов в печальных случаях на самом деле вызывает флеши, с последующей путаницей, такой как фактически не закрытие основного ресурса.
- Похоже, что ваш базовый ресурс - это
URLConnection
, который не имеет метода disconnect
/close
как таковой.
Возможно, вы захотите рассмотреть использование идиомы Execute Around, поэтому вам не нужно дублировать подобные вещи.