PrintWriter autoflush puzzling logic

2019-03-05 06:21发布

问题:

public PrintWriter(OutputStream out, boolean autoFlush):

out - An output stream
autoFlush - A boolean; if true, the println, printf, or format methods
will flush the output buffer

public PrintStream(OutputStream out, boolean autoFlush):

out - The output stream to which values and objects will be printed 
autoFlush - A boolean; if true, the output buffer will be flushed 
whenever a byte array is written, one of the println methods is invoked, 
or a newline character or byte ('\n') is written

What was the reason for changing autoflush logic between these classes?

Because they are always considered as identical except for encoding moments and "autoflush" without flushing on print() hardly corresponds to principle of least astonishment, silly bugs occur:
I created a PrintWriter with autoflush on; why isn't it autoflushing?

回答1:

I think the answer lies in the history of Java. The trio InputStream, OutputStream and PrintStream in java.io date back to Java 1.0. That is before serious support for file encodings and character sets were built into the language.

To quote the Javadoc:

"A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method..."

To summarize, it is a convenience for generating textual output, grafted on top of lower level IO.

In Java 1.1, Reader, Writer and PrintWriter were introduced. Those all support character sets. While InputStream and OutputStream still had a real uses (raw data processing), PrintStream became far less relevant, because printing by nature is about text.

The Javadoc for PrintWriter explicitly states:

Unlike the PrintStream class, if automatic flushing is enabled it will be done only when one of the println() methods is invoked, rather than whenever a newline character happens to be output. The println() methods use the platform's own notion of line separator rather than the newline character.

Put another way, PrintWriter should only be used through the print*(...) APIs, because writing newline characters etc should not be the caller's responsibility, the same way dealing with file encodings and character sets are not the caller's responsibility.

I would argue that PrintWriter should have been java.io.Printer instead, and not have extended Writer. I don't know whether they extended to mimic PrintStream, or because they were stuck on maintaining the pipe design idiom.



回答2:

The reason it wasn't the same at start was probably just an accident. Now it's backwards compatibility.