Skip to content

Instantly share code, notes, and snippets.

@basilevs
Created April 18, 2025 22:00
Show Gist options
  • Save basilevs/cb1a0d3b48b7fd17bdced693d5082508 to your computer and use it in GitHub Desktop.
Save basilevs/cb1a0d3b48b7fd17bdced693d5082508 to your computer and use it in GitHub Desktop.
package org.basilevs.example.flush;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/// Demonstrates that PrintStream does not check for new line character despite documentation mentioning it
public class AutoFlushShouldNotFlushTooOften {
private static final Charset CHARSET = StandardCharsets.UTF_8;
private final static String TEST_DATA = "Text without EOL. It is not supposed to flush";
private final static int BUFFER_SIZE = 10_000; // large enough to to fit test data
public static void main(String[] args) throws IOException, InterruptedException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try ( PrintStream output = new PrintStream(
new BufferedOutputStream(bytes, BUFFER_SIZE), true, CHARSET)) {
/// Documentation for autoFlush = true says:
/// > 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
/// This implies that newline character is significant.
/// However, the flush happens always, even if data has no line breaks.
/// This leads to a minor performance loss, as flush happens on every character, not on every line
/// Arguably, autoFlush should be false for performance, but documentation is still misleading.
/// # Entrypoints
/// - java.io.PrintStream.implWrite(String) - does unconditional charOut.flushBuffer() before content check is done
/// - it leads to java.io.PrintStream.implWrite(byte[], int, int) which has no content check
/// - java.io.PrintStream.implWrite(String) then checks content for new line character, but flush is already done, so the check is redundant
output.print(TEST_DATA); // PrintStream.print() is not expected to flush until a new line character
Thread.sleep(1000);
assertContent("", bytes);
}
assertContent(TEST_DATA, bytes); // PrintStream.close() is expected to flush
}
static void assertContent(String expectedContent, ByteArrayOutputStream flushable) throws IOException {
String flushedContent = new String(flushable.toByteArray(), CHARSET);
if (!Objects.equals(expectedContent, flushedContent)) {
throw new AssertionError("No content is supposed to be flushed, but received: " + flushedContent);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment