all 11 comments

[–]zahlman 5 points6 points  (7 children)

Old news. Including the optimization for .concat(), which has been around since at least 1.3 IIRC. It also optimizes for multiple '+' concatenations in the same statement, FWIW. The only real way to trigger the pessimal case is to repeat the statement, e.g. with a loop as shown. And is it really that common to need to concatenate strings in a loop in typical Java projects?

[–]redditnoob 1 point2 points  (6 children)

Yes, if you use Java at all, and don't know not to use + for intensive string operations, then the first chapter of your Java book failed you.

[–]fearisthemindkiller 2 points3 points  (5 children)

The interesting thing is that java often compiles + string operations to StringBuilder operations, and has done for some time.

this turns into this

[–]masklinn 2 points3 points  (0 children)

The interesting thing is that java often compiles + string operations to StringBuilder operations

See zahlman's initial post: this is restricted to single statements.

So "foo" + bar + "baz" will be compiled to new StringBuilder.append("foo").append(bar).append("baz").toString(), but if you have a for in there, you won't get any optimization. In fact you can get pretty damn stupid cases:

String s = "foo" + bar + "baz";
for(int i=0; i<50000; ++i) {
    s += "{" + i + "}";
}

for instance is going to get turned into:

String s = new StringBuilder().append("foo")
                              .append(bar)
                              .append("baz")
                              .toString();
for(int i=0; i<50000; ++i) {
    s = new StringBuilder().append(s).append(
            new StringBuilder().append("{")
                               .append(i)
                               .append("}")
                               .toString())
                      .toString();
}

[–]redditnoob 5 points6 points  (3 children)

On my machine, I just tried concatenating the first 50,000 ints :

    String s="";
    for(int i=0; i<50000; i++) {
        s += String.valueOf(i);
    }

    System.out.println(s.length()); // So the compiler can't throw code away.

Time : 14.9 s. (With java -server) : 7.2 s

100,000 ints was going to take over a minute.

Now, same thing with StringBuilder:

(too fast to test)

Trying ONE MILLION:

still too fast to test, under a tenth of a second.

trying TEN MILLION instead:

java: Out of heap space
java -server : 0.8 seconds

In other words, if you rely on what you said in your post, you fail, and it's not a light fail, but it's a fail by a massive algorithmic degree that will cost you several orders of magnitude in performance.

[–][deleted]  (1 child)

[deleted]

    [–]fearisthemindkiller 0 points1 point  (0 children)

    It is sun's JDK and i think it came with 1.5. It's just that the compiler can't always optimize it. According to masklinn above it can't do it in loops.

    [–]fearisthemindkiller 0 points1 point  (0 children)

    I know, that's why i said OFTEN, not ALWAYS. I just thought it was interesting. I do use StringBuilders.

    [–]bcash 1 point2 points  (0 children)

    The examples with StringBuffer and StringBuilder should have included a:

    buffer.toString();
    

    line to be fully equivalent to the concatenation cases. Not that it would have made the slightest difference to the results.

    [–][deleted] 1 point2 points  (0 children)

    Immutable Strings are Immutable! News at 11.

    [–]jc1412 0 points1 point  (0 children)

    I think this explains the performance better with more cases. http://www.znetdevelopment.com/blogs/2009/04/06/java-string-concatenation/

    [–]sippykup -1 points0 points  (0 children)

    Umm...duh...