2013-05-22 5 views
5

Этот вопрос состоит из двух частей:
Вам нужно закрыть потоки?

В чем разница между InputStream i1 = new InputStream() и new InputStream()?
и
Стоит ли создавать все локальные переменные только для их закрытия?

Я знаю простые ответы с первой, вы можете сохранить переменную, продолжать использовать переменную и даже закрыть входной поток, как хороший программист. Во-вторых, вы потеряли свою рекомендацию, но она выглядит более кратким. Есть ли разница в памяти между этими двумя? Как насчет разности скоростей (в разрушении)?

Теперь к примерам, которые подтолкнули мои мысли. Сначала мы используем `` новый Object() `, не отбрасывая его.

public void getLongStrings() throws IOException { 
     try { 
      foo = FileCopyUtils.copyToString(new InputStreamReader(aBook.getInputStream())); 
      bar = FileCopyUtils.copyToString(new InputStreamReader(aNovel.getInputStream())); 
     } 
     catch (IOException ioe) { 
      //do something appropriate here; 
     } 
    } 

Теперь для более подробного метода

public void getLongStrings() throws IOException { 
     InputStream i1 = null; 
     InputStream i2 = null; 
     InputStreamReader isr1 = null; 
     InputStreamReader isr2 = null; 
     try { 
      i1 = aBook.getInputStream(); 
      i2 = aNovel.getInputStream(); 
      isr1 = new InputStreamReader(i1); 
      isr2 = new InputStreamReader(i2); 
      foo = FileCopyUtils.copyToString(isr1); 
      bar = FileCopyUtils.copyToString(isr2); 
     } 
     catch (IOException ioe) { 
      //do something appropriate here 
     } finally { 
      if (i1 != null) i1.close(); 
      if (i2 != null) i2.close(); 
      if (isr1 != null) isr1.close(); 
      if (isr2 != null) isr2.close(); 
     } 
    } 

ли первый или второй лучше? Бывает ли одно быстрее другого? Умеет ли закрывать все мои потоки, хотя это не выглядит красиво?

Благодарим за любые идеи (или изменения).

ответ

7

Второе, что вы потеряли ссылку, но оно выглядит более кратким.

Да, это более кратким. Вы делаете меньше с объектом - важно, что вы не делаете то, что делаете должно. При использовании ярлыка часто возникает меньше кода, но, оставляя открытые дескрипторы файлов в ожидании закрытия финализатора, вы обнаружите, что получите исключения, которые трудно воспроизвести надежно.

Есть ли разница в памяти между двумя?

Возможно, но это не имеет значения. Важным ресурсом здесь является не память, а дескриптор файла.

Как насчет разности скоростей (в разрушении)?

Опять же, вероятно, не имеет значения. Правильность гораздо важнее.

(Обратите внимание, что ваш текущий код второго по-прежнему не вполне надежен - если одна из ранних close() вызовов бросает исключение, вы не будете закрывать все остальное.)

Если вы используете Java 7, вы следует посмотреть на try-with-resources statement, что делает все это намного проще.

EDIT: Как указано в ответе JB Nizet, код, который вы используете , может быть уже закрыть базовый поток - это зависит от того, что FileCopyUtils есть. Если это класс Весны, вы в порядке. Если это что-то еще, вы, возможно, не будете. Вы должны прочитать документацию.Общий принцип такой же, как и выше: вы должны убедиться, что что-то закрывает потоки. Не предполагайте, что только потому, что в этом случае вам не нужно закрывать вещи явно, это верно в общем случае.

Обратите внимание, что Guava «s InputSupplier и OutputSupplier интерфейсов полезны здесь - это позволяет обойти поставщик, зная, что ввод/вывод не был открыт еще ... это означает, что другой код может выполнять открывать/копировать/закрывать (или что-то еще требуется) и обрабатывать все это для вас ... вы не можете использовать какие-либо объекты в своем коде, которые может быть закрытым.

+0

Собственно, первый фрагмент верен. См. Мой ответ. –

+0

@JBNizet: Правильно * если * используется код, который автоматически закрывается. Но вы делаете предположение, и OP должен знать, что потоки * должны быть закрыты *, кто бы ни закрыл его. Будет редактировать, хотя. –

+0

Разве это не то, что я сказал в своем ответе? –

1

Предполагая, FileCopyUtils.copyToString()не закрыть предоставленный поток, тогда второй подход лучше.

close() необходимо вызвать для освобождения любых ресурсов, связанных с потоком. Так что дело не в хорошем качестве или производительности кода, а в правильности.

Второй подход имеет ошибку, когда любой из вызовов close вызывает исключение, все остальные вызовы close() не будут вызываться.

+0

Как упоминал Джон Скит, второй подход не совсем правильный. И, как я заметил, первая на самом деле правильная. См. Мой ответ. –

+0

@JBNizet согласился, что есть «более правильно (хотя и не полностью)», но нормально, правильность двоичная, правильная или неправильная, поэтому я обновлю ответ. –

4

Предполагая, что это FileCopyUtils весны, its javadoc говорит:

Все способы копирования использовать размер блока 4096 байт, и закройте все пораженные потоки, когда сделали.

(курсив мой)

Таким образом, ваш подход Начальное прекрасно в этом случае: Spring обрабатывает закрытие чтения и закрытие чтения закрывает обернутый поток.

Если это не так, вам нужно закрыть Reader, желательно используя Java 7's попробуйте с ресурсами.

Обратите внимание, что ваш второй пример закрывает поток, но не обязательно: закрытие считывателя автоматически закрывает его. Также обратите внимание, что если первый читатель не может быть закрыт и выбрасывает исключение IOException, второй не будет закрыт правильно. Еще одна веская причина для использования попробуйте с ресурсами, которым гарантировано закрыть все.

+0

Хорошо знать о весне, я не знал. – SyntaxRules

Смежные вопросы