I was checking out this similar post , the top answer of which says there's "no performance difference whatsoever" between + and StringBuilder.append() because the former will be turned into the latter by JVM.
However per my benchmark, the + way is always about ~20% faster than the StringBuilder way (I'm on Java17, running Intel core i7):
    @State(Scope.Thread)
    public static class BenchState {
        private String a = "A";
        private String b = "B";
        private String c = "C";
    }
    @Benchmark
    public void bmStringConcat(final BenchState state, final Blackhole blackhole) {
        String a = state.a;
        String b = state.b;
        String c = state.c;
        final String s = "{a:" + a + ", b:" + b + ", c: " + c + "}";
        blackhole.consume(s);
    }
    @Benchmark
    public void bmStringBuilder(final BenchState state, final Blackhole blackhole) {
        String a = state.a;
        String b = state.b;
        String c = state.c;
        StringBuilder sb = new StringBuilder();
        final String s = sb.append("{a:").append(a)
                .append(", b:").append(b)
                .append(", c:").append(c)
                .append("}")
                .toString();
        blackhole.consume(s);
    }
Is it because the "+" version "is converted to invokedynamic call" as mentioned here .
Or there are more reasons?
