benf.org :  other :  cfr :  Stringbuilder vs concatentation

This is a really well known bit of rewriting that javac does on your original code. It's also quite interesting, because it's one of the rare cases where javac actually emits an optimisation - because strings are immutable in java, concatenation is very expensive compared to using a stringbuilder. So for simple string "building", javac uses a temporary string builder.

Original

    public void test(int end) {
        char ch;
        int x = 0;
        while ((ch = foo[++x]) != '*') {
            System.out.println("" + x + ": " + ch);
        }
    }

CFR decompiled (with --stringbuilder false)

    public void test(int end) {
        char ch;
        int x = 0;
        while ((ch = this.foo[++x]) != '*') {
            System.out.println(new StringBuilder().append("").append(x).append(": ").append(ch).toString());
        }
    }

CFR decompiled (with default behaviour)

    public void test(int end) {
        char ch;
        int x = 0;
        while ((ch = this.foo[++x]) != '*') {
            System.out.println(("" + x + ": " + ch));
        }
    }

Prior to java 1.5, StringBuffer was used (it has issues with uneccessary (poor) synchronisation, so it was dropped in this transformation in favour of StringBuilder). CFR (0_44+) will detect the version of java your class file was compiled with, and will selectively enable the appropriate resugaring (StringBuffer or StringBuilder).

Note also - in java 9+, string catenation with non constants is longer implemented with StringBuilder, but uses StringConcatFactory.

You can override this resugaring behaviour with --stringbuilder true / --stringbuffer true / --stringconcat true (or false, gosh).

Note - when all elements are compile time constants, instead of an intermediate StringBuilder, the expressions will be constant folded - see constant-folding.


Last updated 02/2014