Why does "B" lag while "#" flies? Solving the cult Java question
\n\nIf you've ever written simple loops in Java to output characters to the console, you might have noticed a peculiarity: printing the lowercase letter 'B' can be noticeably slower than printing the hash symbol '#'. This effect once exploded on Stack Overflow — the question garnered thousands of views and votes. Today, we'll figure out what lies behind this phenomenon and how it relates to the internal mechanisms of Java, console I/O, and buffering.
Setting up the experiment
\nImagine we run two loops that print 100,000 characters each to the console: one loop outputs '#', the other outputs 'B'. At first glance, the operation is identical. However, on many systems (especially Windows), the first loop finishes in ~100 ms, while the second takes several seconds. Why?
Let's reproduce this in Java.
\n\nTest code
\npublic class SlowPrintTest {\n public static void main(String[] args) {\n long start = System.nanoTime();\n for (int i = 0; i < 100_000; i++) {\n System.out.print("#");\n }\n long end = System.nanoTime();\n System.out.println("\\nTime for '#': " + (end - start) / 1_000_000 + " ms");\n\n start = System.nanoTime();\n for (int i = 0; i < 100_000; i++) {\n System.out.print("B");\n }\n end = System.nanoTime();\n System.out.println("\\nTime for 'B': " + (end - start) / 1_000_000 + " ms");\n }\n}\n\nRun this code in a terminal, not in an IDE (e.g., via java SlowPrintTest). The result will surprise you. On Windows with CMD, the difference can be 10–50 times.
Why does this happen? The root cause — font rendering
\nThe issue is not with System.out.print() itself or the JVM. The main reason lies in how the operating system and terminal handle character output. System.out in Java is a wrapper around the standard output stream (stdout). Data is passed to the console, but the speed of on-screen display depends on:
- \n
- Character width — many older consoles (e.g., CMD on Windows) use monospaced fonts, but the character
'B'may require more complex rendering than'#'. \n - Screen updates — the console may perform a full line redraw when outputting each character, rather than simply appending it. \n
- Terminal buffering — some terminals buffer output in blocks, but if a character requires glyph width calculation, it slows things down. \n
The effect is most pronounced in the Windows Command Prompt (CMD) with raster fonts. When you print 'B', the console tries to display the character in graphics mode, while for '#' it uses a simplified approach. In modern terminals (Windows Terminal, iTerm2, Alacritty), the difference may be less noticeable or absent.
The role of buffering in Java
\nAn important aspect of output optimization is using buffered streams. System.out is not buffered by default (more precisely, it is buffered at the JVM level, but with a small size). Each call to print() can trigger a system write() call, which is very expensive. If we add buffering via BufferedWriter, performance improves, but the difference between characters remains — it's on the terminal side.
// Example with buffering\nBufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));\nfor (int i = 0; i < 100_000; i++) {\n bw.write("#");\n}\nbw.flush();\n\nEven with buffering, if the terminal renders 'B' slowly, the total time will increase. One