String Concatenation in Java — Level 2

A developer-focused deep dive into how Java builds strings at runtime. Learn what objects are created when using the + operator, how StringBuilder avoids extra allocations, and when each approach is best.

Author

Mr. Oz

Date

Read

10 mins

Level 2

Illustration representing Java string concatenation internals

Author

Mr. Oz

Date

Read

10 mins

Share

Java strings are immutable. Concatenation with + is compiled to use a builder under the hood, but the lifecycle of that builder depends on where the expression sits. In tight loops, using + can create many short‑lived objects; a single StringBuilder reused across iterations avoids those allocations.

  1. What gets created with +

    For a single expression like "Hello " + name + "!", the compiler emits something like new StringBuilder().append(...).toString(). That means 1 StringBuilder instance and 1 resulting String object at runtime.

    // Roughly equivalent desugaring
    String result = new StringBuilder()
      .append("Hello ")
      .append(name)
      .append("!")
      .toString();

    Inside a loop, however, s += part; becomes new StringBuilder(s).append(part).toString() on every iteration: that is 1 new StringBuilder and 1 new String per iteration.

    String s = "";
    for (String part : parts) {
      s += part; // each iteration: new StringBuilder + new String
    }
  2. What gets created with StringBuilder

    With an explicit StringBuilder, you allocate 1 builder and 1 final String. Intermediate steps are in the same mutable buffer.

    StringBuilder sb = new StringBuilder();
    for (String part : parts) {
      sb.append(part);
    }
    String s = sb.toString(); // one final String object
  3. Compile‑time constants are folded

    Concatenations of literals are resolved at compile time with zero runtime allocation.

    String a = "Hello" + ", " + "world"; // constant folded by compiler
  4. Java 9+ note: invokedynamic concat

    Modern JDKs may use StringConcatFactory via invokedynamic for +. The guidance remains: prefer a single builder in loops.

  5. Practical guidelines

    • Use + for a handful of concatenations outside loops.
    • In loops, use StringBuilder.
    • Pre‑size the builder when possible: new StringBuilder(estimatedSize).
    • Prefer String.join for joining with delimiters.

Tips and pitfalls

  • Beware of s += x inside nested loops.
  • append(int), append(double) avoid boxing.
  • Benchmark with JMH for hot paths.