Подтвердить что ты не робот

Закрытие входных потоков в Java

У меня есть следующий фрагмент кода в блоке try/catch

 InputStream inputstream = conn.getInputStream();
 InputStreamReader inputstreamreader = new  InputStreamReader(inputstream);
 BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

Мой вопрос в том, что когда мне нужно закрыть эти потоки в блоке finally, мне нужно закрыть все 3 потока или просто закрыть befferedreader закроет все остальные потоки?

4b9b3361

Ответ 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, поэтому вам не нужно дублировать подобные вещи.