JDK-8325730 : StringBuilder.toString allocation for the empty String
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 21,22,23
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2024-02-12
  • Updated: 2024-04-29
  • Resolved: 2024-02-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 21 JDK 22 JDK 23
21.0.5-oracleUnresolved 22.0.2Fixed 23 b11Fixed
Related Reports
Relates :  
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
In Java 17 StringBuilder.toString was calling StringLatin1.newString that returned a literal "" for len == 0. After https://bugs.openjdk.org/browse/JDK-8282429 https://github.com/openjdk/jdk/commit/bab431cc120fe09be371dadef0c1caf79ec9eef4 Java 21 returns a new String object each time.  While it is minor, it still looks like a regression that effects such code paths as deserialisation.

REGRESSION : Last worked in version 17.0.10

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
new StringBuilder().toString() == ""

ACTUAL -
false

---------- BEGIN SOURCE ----------
public class Test {
    public static void main(String[] args) {
        System.out.println(new StringBuilder().toString() == "");
    }
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
That spec should probably be rewritten to allow for a pre-allocated `String` to be returned to better reflect long standing behavior. E.g. `StringBuffer` will (somewhat awkwardly) return a cached string on repeat `toString()` calls since https://bugs.openjdk.org/browse/JDK-8013395 (8). Edit: scratch that, except for "" StringBuffer::toString always returns a new String.
15-03-2024

The backport to jdk21u prompted me to look at `AbstractStringBuilder.toString` spec, which says: ``` /** * Returns a string representing the data in this sequence. * A new {@code String} object is allocated and initialized to * contain the character sequence currently represented by this * object. This {@code String} is then returned. Subsequent * changes to this sequence do not affect the contents of the * {@code String}. * * @return a string representation of this sequence of characters. */ @Override public abstract String toString(); ``` I read it as: a new string is _always_ allocated with `toString()`, which means `return ""` is against the spec?
14-03-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk21u-dev/pull/364 Date: 2024-03-13 19:21:42 +0000
14-03-2024

[jdk22u-fix-request] Approval Request from Aleksey Shipilëv Clean backport to fix the regression introduced in JDK 19. Applies cleanly. Tests pass. The benchmark improvements are the same as in mainline.
05-03-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk22u/pull/70 Date: 2024-02-27 15:17:21 +0000
27-02-2024

Changeset: d2590c69 Author: Claes Redestad <redestad@openjdk.org> Date: 2024-02-20 20:28:55 +0000 URL: https://git.openjdk.org/jdk/commit/d2590c69b4efe5aa2b48b08070e0dbafb04ef202
20-02-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/17931 Date: 2024-02-20 16:32:54 +0000
20-02-2024

Yes, this is a regression. The microbenchmark that was added when this optimization was put in place (https://bugs.openjdk.org/browse/JDK-8240094) only covered String API, not StringBuilder.toString. I'll amend that.
20-02-2024

Will fix to eliminate additional string pressure but the user should not rely on equality. Bad practice. Recommend new StringBuilder().toString().isEmpty().
20-02-2024

The observations onmacOS: JDK 21 output : false JDK 11.0.20 output : false JDK 17.0.10 output : true >> Failed
13-02-2024