Course – LS – All
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Introduction

The System.out stream is the fundamental feature of Java language, which is commonly used for producing console outputs. Whether using it to print our first “Hello, World!” or debug complex applications, we’ll likely encounter System.out.

In this tutorial, we’ll discuss when to call System.out.flush() in Java.

2. Buffering Concept

Buffering is a fundamental concept in computing, especially regarding I/O operations. In the context of output streams, buffering refers to the temporary data storage before it’s written out. Once this buffer reaches its capacity or is explicitly flushed, the accumulated data is written out in a single go.

However, this buffering mechanism can sometimes lead to unexpected behavior. Data might not appear immediately where expected, leading to potential confusion. This is where understanding the role of the flush() method becomes crucial, ensuring that buffered data is written out when necessary.

3. The Basics of Flushing in Java

While buffering provides an efficient way to handle data, there comes a time when the buffered data needs to be sent to its intended destination immediately, regardless of whether the buffer is full. This action is known as flushing.

Not seeing the expected output immediately can be confusing when dealing with output streams. This delay is often due to the buffered data not yet being written to its destination. Flushing ensures that any data currently in the buffer is immediately written out, giving developers a real-time view of their outputs:

Buffer Diagram

Java provides a built-in mechanism to explicitly flush output streams, namely the flush() method. This method is part of the OutputStream class and its subclasses, including the type behind System.out. When invoked, the flush() method ensures that any buffered data in the stream is immediately written out:

public void flush() {
    if (lock != null) {
        lock.lock();
        try {
            implFlush();
        } finally {
            lock.unlock();
        }
    } else {
        synchronized (this) {
            implFlush();
        }
    }
}

4. Flushing with System.out

The behavior of System.out is determined by the JVM’s specific implementation. In many scenarios, the underlying PrintStream is configured with autoFlush enabled. This automatic flushing is why developers often don’t need to invoke the flush operation explicitly.

Most of the writing methods have some checks for autoflush. They might be different, but we can see the general idea in PrintStream.implWriteln():

private void implWriteln(char[] buf) throws IOException {
    ensureOpen();
    textOut.write(buf);
    textOut.newLine();
    textOut.flushBuffer();
    charOut.flushBuffer();
    if (autoFlush)
        out.flush();
}

However, it’s worth noting that certain JVM implementations or frameworks might offer custom implementations of System.out. For instance, JUnit might disable autoFlush to optimize the display of test output.

While some sources discuss the differences between the print and println methods in relation to flushing, a closer look at the PrintStream implementation reveals no distinct behavior between the two in terms of automatic flushing. However, as mentioned previously, we should examine the actual implementation of the System.out to be sure of its behavior.

5. Conclusion

For many developers, System.out functions seamlessly without the need to delve into its underlying mechanics or the intricacies of flushing behavior. It’s important to remember, however, that the behavior of System.out is contingent upon the platform’s specific implementation, which can introduce variations.

While basic applications, like the quintessential “Hello, World”, remain unaffected by buffering and flushing nuances, the story changes when we venture into more complex domains. In contexts such as advanced logging or testing frameworks, tampering with the default implementation or overusing explicit flush operations can have performance implications. It’s always prudent to strike a balance, ensuring the application’s performance remains optimal while achieving the desired output behavior.

Course – LS – All
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

res – REST with Spring (eBook) (everywhere)