Fundamentals 17 min read

How Java’s String Concatenation Evolved: From '+' to Hidden Classes

This article traces the evolution of Java string concatenation from the simple '+' operator through JDK 8’s StringBuilder implementation, the JDK 9+ StringConcatFactory with invokedynamic, and Alibaba’s PR 20273 that introduces hidden‑class bytecode generation, highlighting performance gains and startup‑time improvements.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How Java’s String Concatenation Evolved: From '+' to Hidden Classes

Overview

The article explains the evolution of Java string concatenation techniques and Alibaba’s recent contributions (PR 20273) that improve performance and startup time.

1. Using "+" for String Concatenation

Older articles claim that using "+" is slow, but since JDK 9+ the "+" operator is faster than a manual StringBuilder in many cases.

class Demo {
    public static String concatIndy(int i) {
        return "value " + i;
    }
}

2. JDK 8 Implementation

In JDK 8, the compiler translates "+" into bytecode that creates a StringBuilder, appends the value, and calls toString(). The generated bytecode is equivalent to writing the StringBuilder code directly, so using "+" is more concise while having the same performance.

public static String concatIndy(int i) {
    return new StringBuilder("value ")
        .append(i)
        .toString();
}

3. JDK 9+ (JEP 280) Implementation

From JDK 9 onward, the compiler emits an invokedynamic call to StringConcatFactory.makeConcatWithConstants, which generates a method at runtime to perform concatenation without allocating a StringBuilder. This reduces GC pressure and avoids extra array copies.

public static String concatIndy(int i) {
    // bytecode uses invokedynamic to call makeConcatWithConstants
}

Benchmark on JDK 11 shows the "+" version (concatIndy) is about 11% faster than the explicit StringBuilder version.

Benchmark                Mode  Cnt   Score   Error  Units
ConcatBench.concatIndy   thrpt   5  130.841 ± 1.127 ops/us
ConcatBench.concatSB    thrpt   5  117.897 ± 1.437 ops/us

4. Implementation Details of StringConcatFactory

The factory uses MethodHandles to build a dynamic call site that assembles the final string. While powerful, the MethodHandle expression can generate many intermediate classes and increase JIT compilation cost, especially when many arguments are involved.

Since JDK 23, the JVM option java.lang.invoke.StringConcat.highArityThreshold (default 20) switches back to StringBuilder for high‑arity concatenations to mitigate this cost.

5. Alibaba’s PR 20273

Alibaba engineer Wen Shaojin submitted PR 20273 (July 2024) which replaces the MethodHandle‑based implementation with a hidden‑class bytecode generator. The hidden class stores constants as fields, avoiding the length‑coder long value and allowing better inlining by the C2 compiler.

package java.lang.invoke;

class StringConcatFactory {
    static final class InlineHiddenClassStrategy {
        static MethodHandle generate(Lookup lookup, MethodType args, String[] constants) {
            byte[] classBytes = ClassFile.of().build(...);
            var hiddenClass = lookup.makeHiddenClassDefiner(...).defineClass(true, null);
            var constructor = lookup.findConstructor(hiddenClass, CONSTRUCTOR_METHOD_TYPE);
            var concat = lookup.findVirtual(hiddenClass, METHOD_NAME, concatArgs);
            var instance = hiddenClass.cast(constructor.invoke(constants));
            return concat.bindTo(instance);
        }
    }
}

Performance tests show the new implementation matches the speed of the previous MethodHandle version while dramatically reducing startup overhead and the number of generated intermediate classes.

6. Additional Alibaba Contributions

PR 20253 – Optimizes StringConcatHelper.simpleConcat (≈8% faster for non‑simple types).

PR 19730 – Reduces object allocation for FloatToDecimal and DoubleToDecimal.

PR 14699 – Improves Integer.toString and StringBuilder.append(int/long) (up to 242% faster).

PR 14578 – Optimizes UUID.toString.

PR 14751 – Improves upper/lower case conversion speed.

PR 15768 – Optimizes HexFormat.formatHex.

PR 15776 – Optimizes String.format.

PR 19513 – Optimizes java.text.Format.

7. Summary

In JDK 8, using "+" is equivalent in performance to an explicit StringBuilder.

From JDK 11 onward, the "+" operator becomes faster than StringBuilder and reduces GC overhead.

High‑arity concatenations in JDK 9‑23 suffer from slower startup and higher JIT cost.

Alibaba’s PR 20273 introduces a hidden‑class based implementation that retains runtime performance while solving the startup‑time problem; it will become the default in JDK 24.

Beyond PR 20273, Alibaba has contributed many other OpenJDK improvements across GC, JIT, runtime, and core libraries.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performanceJDKhidden classOpenJDKString concatenationMethodHandles
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.