Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8339189

BufferedReader doesn't read full \r\n line ending when it doesn't fit in buffer

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 24
    • core-libs
    • None
    • behavioral
    • minimal
    • Tiny risk as we are only clarifying existing behavior.
    • Java API
    • SE

      Summary

      Update the specification of the java.io.Buffered{InputStream,OutputStream,Reader,Writer} classes to indicate that more than one instance of such a class should not be used with the same respective instance of an underlying {InputStream,OutputStream,Reader,Writer} as the buffering classes maintain their own state and the results would be unpredictable.

      Problem

      The specifications of the java.io buffering wrapper classes do not explicitly state that using more than one instance of such a class on the same instance of the underlying, wrapped class can give different results from using a single wrapper instance with the same underlying instance.

      Solution

      Add verbiage to the wrapper classes indicating that each instance maintains its own state.

      Specification

      --- a/src/java.base/share/classes/java/io/BufferedInputStream.java
      +++ b/src/java.base/share/classes/java/io/BufferedInputStream.java
      @@ -48,10 +48,15 @@
        * causes all the  bytes read since the most
        * recent {@code mark} operation to be
        * reread before new bytes are  taken from
        * the contained input stream.
        *
      + * @apiNote
      + * Once wrapped in a {@code BufferedInputStream}, the underlying
      + * {@code InputStream} should not be used directly nor wrapped with
      + * another stream.
      + *
        * @author  Arthur van Hoff
        * @since   1.0
        */
       public class BufferedInputStream extends FilterInputStream {
      
      --- a/src/java.base/share/classes/java/io/BufferedOutputStream.java
      +++ b/src/java.base/share/classes/java/io/BufferedOutputStream.java
      @@ -33,10 +33,15 @@
        * The class implements a buffered output stream. By setting up such
        * an output stream, an application can write bytes to the underlying
        * output stream without necessarily causing a call to the underlying
        * system for each byte written.
        *
      + * @apiNote
      + * Once wrapped in a {@code BufferedOutputStream}, the underlying
      + * {@code OutputStream} should not be used directly nor wrapped with
      + * another stream.
      + *
        * @author  Arthur van Hoff
        * @since   1.0
        */
       public class BufferedOutputStream extends FilterOutputStream {
           private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512;
      
      --- a/src/java.base/share/classes/java/io/BufferedReader.java
      +++ b/src/java.base/share/classes/java/io/BufferedReader.java
      @@ -41,25 +41,32 @@
        * <p> The buffer size may be specified, or the default size may be used.  The
        * default is large enough for most purposes.
        *
        * <p> In general, each read request made of a Reader causes a corresponding
        * read request to be made of the underlying character or byte stream.  It is
      - * therefore advisable to wrap a BufferedReader around any Reader whose read()
      - * operations may be costly, such as FileReaders and InputStreamReaders.  For
      + * therefore advisable to wrap a {@code BufferedReader} around any
      + * {@code Reader} whose {@code read()} operations may be costly, such as
      + * {@code FileReader}s and {@code InputStreamReader}s.  For
        * example,
        *
        * {@snippet lang=java :
        *     BufferedReader in = new BufferedReader(new FileReader("foo.in"));
        * }
        *
        * will buffer the input from the specified file.  Without buffering, each
      - * invocation of read() or readLine() could cause bytes to be read from the
      - * file, converted into characters, and then returned, which can be very
      - * inefficient.
      + * invocation of {@code read()} or {@code readLine()} could cause bytes to be
      + * read from the file, converted into characters, and then returned, which can
      + * be very inefficient.
        *
      - * <p> Programs that use DataInputStreams for textual input can be localized by
      - * replacing each DataInputStream with an appropriate BufferedReader.
      + * <p> Programs that use {@code DataInputStream}s for textual input can be
      + * localized by replacing each {@code DataInputStream} with an appropriate
      + * {@code BufferedReader}.
      + *
      + * @apiNote
      + * Once wrapped in a {@code BufferedReader}, the underlying
      + * {@code Reader} should not be used directly nor wrapped with
      + * another reader.
        *
        * @see FileReader
        * @see InputStreamReader
        * @see java.nio.file.Files#newBufferedReader
        *
      --- a/src/java.base/share/classes/java/io/BufferedWriter.java
      +++ b/src/java.base/share/classes/java/io/BufferedWriter.java
      @@ -35,29 +35,35 @@
        * provide for the efficient writing of single characters, arrays, and strings.
        *
        * <p> The buffer size may be specified, or the default size may be accepted.
        * The default is large enough for most purposes.
        *
      - * <p> A newLine() method is provided, which uses the platform's own notion of
      - * line separator as defined by the system property {@code line.separator}.
      - * Not all platforms use the newline character ('\n') to terminate lines.
      - * Calling this method to terminate each output line is therefore preferred to
      - * writing a newline character directly.
      + * <p> A {@code newLine()} method is provided, which uses the platform's own
      + * notion of line separator as defined by the system property
      + * {@linkplain System#lineSeparator() line.separator}. Not all platforms use the newline character ('\n')
      + * to terminate lines. Calling this method to terminate each output line is
      + * therefore preferred to writing a newline character directly.
        *
      - * <p> In general, a Writer sends its output immediately to the underlying
      - * character or byte stream.  Unless prompt output is required, it is advisable
      - * to wrap a BufferedWriter around any Writer whose write() operations may be
      - * costly, such as FileWriters and OutputStreamWriters.  For example,
      + * <p> In general, a {@code Writer} sends its output immediately to the
      + * underlying character or byte stream.  Unless prompt output is required, it
      + * is advisable to wrap a {@code BufferedWriter} around any {@code Writer} whose
      + * {@code write()} operations may be costly, such as {@code FileWriter}s and
      + * {@code OutputStreamWriter}s.  For example,
        *
        * {@snippet lang=java :
        *     PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
        * }
        *
      - * will buffer the PrintWriter's output to the file.  Without buffering, each
      - * invocation of a print() method would cause characters to be converted into
      - * bytes that would then be written immediately to the file, which can be very
      - * inefficient.
      + * will buffer the {@code PrintWriter}'s output to the file.  Without buffering,
      + * each invocation of a {@code print()} method would cause characters to be
      + * converted into bytes that would then be written immediately to the file,
      + * which can be very inefficient.
      + *
      + * @apiNote
      + * Once wrapped in a {@code BufferedWriter}, the underlying
      + * {@code Writer} should not be used directly nor wrapped with
      + * another writer.
        *
        * @see PrintWriter
        * @see FileWriter
        * @see OutputStreamWriter
        * @see java.nio.file.Files#newBufferedWriter

            bpb Brian Burkhalter
            webbuggrp Webbug Group
            Jaikiran Pai
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: