JDK-8171895 : PrintWriter.print(double) / PrintWriter.print(float) is slow
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 8,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2016-12-21
  • Updated: 2022-07-20
  • Resolved: 2022-07-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 19
19Resolved
Related Reports
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
When PrintWriter.print(double) or PrintWriter.print(float) are invoked, they call String.valueOf(d) to convert the floating point argument to a string before appending the String's characters to the stream. This creates unnecessary intermediate objects.

StringBuilder uses a much more efficient implementation. It calls FloatingDecimal.appendTo(double, Appendable) which formats the number to a reusable buffer, avoiding unnecessary allocation. PrintWriter implements Appendable, so it ought to be able to use almost exactly the same implementation.

Note that the BinaryToASCIIConverters in FloatingDecimal don't actually handle all Appendable implementors: they special-case StringBuilder and StringBuffer, but it is trivial to also add a special case for PrintWriter here.

JUSTIFICATION :
PrintWriter is unnecessarily slow. Its performance can be easily improved by reusing an existing optimization. (Note that a similar enhancement for char was implemented in Java 1.4; see https://bugs.openjdk.java.net/browse/JDK-4350734)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
pw.print(1.0d) should not allocate garbage objects.
ACTUAL -
pw.print(1.0d) allocates a short-lived String, which immediately becomes garbage. Because of the complexity of formatting floating point numbers, escape analysis is very unlikely to remove this allocation.


Comments
A simple benchmark run on JDK 18 and on the development version of JDK 20 on PrintWriter.write(double) gave these results: JDK 18 Benchmark Mode Cnt Score Error Units MyBenchmark.printDouble thrpt 10 4212147.015 ± 87378.800 ops/s JDK 20-internal Benchmark Mode Cnt Score Error Units MyBenchmark.printDouble thrpt 10 11214267.222 ± 282150.820 ops/s The JDK 20-internal throughput is nearly thrice that of JDK 18, presumably because of the fix for JDK-4511638 which was integrated in JDK 19. Resolving as Not an Issue.
20-07-2022

String.valueOf() is public static String valueOf(double d) { return Double.toString(d); } so once JDK-4511638 is resolved then the present issue ought to be resolved as Not an Issue.
17-02-2022