Почему это необходимо для буферизации входного потока? Почему мы не можем это делать, используя только входной поток? [Дубликат]

Чтобы использовать методы и член объекта, вам сначала нужно создать этот объект. Если вы его не создали (переменная, которая должна содержать объект, не инициализируется), но вы пытаетесь использовать его методы или переменные, вы получите эту ошибку.

Иногда вы можете просто забыть инициализировать .

Отредактировано: new не может вернуть значение null, но исключение огня при ошибке. Давно это было на некоторых языках, но не больше. Спасибо @John Saunders за указание на это.

36
задан geejay 3 June 2010 в 08:36
поделиться

4 ответа

Я бы этого не сделал, я бы оставил его на самом высоком уровне абстракции. Если вы не собираетесь использовать возможности BufferStream для меток и сброса, зачем их обертывать?

Если потребитель нуждается в нем, лучше его обернуть.

6
ответ дан Drew Noakes 25 August 2018 в 00:27
поделиться
  • 1
    Это, по-видимому, означает, что метки и сброс являются единственными полезными вещами, которые BufferedInputStream добавляет к простой InputStream. Это может быть справедливо с точки зрения API, но, как говорили другие, BufferedInputStream заботится о буферизации чтения для вас. Чтение байта по времени от голого FileInputStream в 40 раз медленнее, чем чтение из одного, завернутого в BufferedInputStream. Тем не менее, верните InputStream и сохраните подпись своего метода как таковой. Пользователи могут обернуть, если они того пожелают. – jasonmp85 3 June 2010 в 09:06
  • 2
    Я согласен с тем, что с точки зрения производительности лучше обернуть его в 99,9% случаев. Однако он освобождает потребителя от ответственности за то, как использовать InputStream. Подобные предположения от потребителя ограничивают возможность повторного использования. – Peter Tillemans 3 June 2010 в 09:19
  • 3
    Я думаю, что в более чем 0,1% случаев потребитель не будет читать один байт за раз и вместо этого сам будет использовать какой-то буфер, и в этом случае BufferedInputStream будет бесполезным накладными расходами. – Michael Borgwardt 3 June 2010 в 11:19
  • 4
    @Michael, я думаю, что точка зрения Питера заключается в том, что он будет быстрее, чем байт за байтом в 99% случаев, а не в 99% случаев, когда он будет использоваться в качестве байтового байта. – Yishai 3 June 2010 в 12:24

Возможно, вам не всегда нужна буферизация, поэтому ответ будет «Нет», в некоторых случаях это просто накладные расходы.

Есть еще одна причина: «Нет», и это может быть более серьезным. BufferedInputStream (или BufferedReader) может привести к непредсказуемым сбоям при использовании с сетевым сокетом, когда вы также включили тайм-аут в сокете. Тайм-аут может возникать при чтении пакета. Вы больше не сможете получить доступ к данным, которые были перенесены в эту точку, даже если вы знали, что существует некоторое ненулевое количество байтов (см. java.net.SocketTimeoutException, который является подклассом java.io.InterruptedIOException, поэтому имеет переменную bytesTransferred доступно.)

Если вам интересно, как может произойти тайм-аут сокета во время чтения, просто подумайте о вызове метода read(bytes[]) и исходного пакета, который содержит сообщение, в результате которого был разделен, но один из частичных пакетов задерживается за пределами таймаута (или оставшейся части таймаута). Это может произойти чаще, когда снова завертывается в то, что реализует java.io.DataInput (любое из чтений для нескольких байтовых значений, например readLong() или readFully() или BufferedReader.readLine().

Обратите внимание, что java.io.DataInputStream также является плохим кандидатом для потоков сокетов, у которых есть тайм-аут, так как он не ведет себя хорошо с исключениями тайм-аута.

2
ответ дан Kevin Brock 25 August 2018 в 00:27
поделиться
  • 1
    Что касается BufferedInputStream и BufferedReader, это городской миф. Если вы получили таймаут чтения, (i) вы читаете, ergo внутренний буфер был пуст, иначе вы не читали; (ii) никакие данные не поступали в течение периода ожидания. Ergo данных не теряется. Попробуй. – user207421 4 June 2010 в 01:54
  • 2
    @EJP: Ты меня задумался, но я все еще думаю, что это может быть проблемой. Когда буферизованный поток действительно должен выполнять ввод / вывод (заполнять буфер), тогда это точка, когда вы можете получить исключение тайм-аута и внутренние переменные для отслеживания того, сколько байтов в буфере не будет обновлено. Я попытался проверить это, но, хотя я могу реплицировать исключения тайм-аута, я пока не могу воспроизвести ситуацию, когда bytesTransferred отличен от нуля. До тех пор я не могу доказать это так или иначе. [Я потерял данные с DataInputStream и таймаутом.] – Kevin Brock 4 June 2010 в 12:18
  • 3
    @EJP: Возможно, тогда чтение байтового массива из сокета никогда не приведет к частичному буферу чтения из-за таймаута, а затем bytesTransferred никогда не будет отличным от нуля (иначе BufferredInputStream завершится с ошибкой). Это может быть также случай, когда реализация JVM на разных платформах / поставщиках может давать разные результаты - я только что тестировал в Windows 7 с помощью Sun / Oracle Java. – Kevin Brock 4 June 2010 в 12:34
  • 4
    Но BufferedInputStream не заполняет буфер. См. Javadoc. Он читает все, что нужно читать, как и любое другое чтение, и возвращает эту длину. В частности, он никогда не блокирует дважды. Если какие-либо данные поступают в течение таймаута, нет таймаута. И наоборот, если есть тайм-аут, данных не поступало. Так что ничего не потеряно. Что касается DataInputStream, проблема реальна. Что касается BufferedInputStream, нет. – user207421 6 June 2010 в 09:30

Это также зависит от того, как вы собираетесь читать из InputStream. Если вы собираетесь читать его символ / байт за раз (т. Е. Read ()), то BufferedInputStream уменьшит ваши накладные расходы, пошаговое выполнение массового чтения от вашего имени. Если вы собираетесь читать его в массив 4k или 8k byte / char, блок за раз тогда BuffredInputStream, вероятно, вам не пригодится.

0
ответ дан Paul Jowett 25 August 2018 в 00:27
поделиться

Имеет ли смысл always переносить InputStream как BufferedInputStream, когда я знаю, является ли данный InputStream чем-то иным, чем буферизированным?

Нет .

Имеет смысл, если вы, вероятно, будете выполнять множество небольших чтений (один байт или несколько байтов за раз), или если вы хотите использовать некоторые функции более высокого уровня, предлагаемые буферизованными API ; например, BufferedReader.readLine().

Однако, если вы собираетесь выполнять большие чтения блоков с использованием методов read(byte[]) и / или read(byte[], int, int), обертывание InputStream в BufferedInputStream не помогает.

(В ответ на комментарий @Peter Tillman по его собственному ответу, блок чтения прецедентов определенно представляет более 0,1% использования классов InputStream !! Однако он прав в том смысле, что обычно безвреден использовать буферный API, когда вам это не нужно.)

30
ответ дан Stephen C 25 August 2018 в 00:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: