views:

1916

answers:

11

Given the 2 toString() implementations below, which is prefered

public String toString(){
    return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}

or

public String toString(){
    StringBuilder sb = new StringBuilder(100);
    return sb.append("{a:").append(a)
          .append(", b:").append(b)
          .append(", c:").append(c)
          .append("}")
          .toString();
}

More importantly given we have only 3 properties it might not make a difference, but at what point do you switch from concat to builder?

+1  A: 

Rather than answer your question (sorry!) I'll suggest that you find out for yourself by benchmarking the two solutions. You could even examine the bytecode emitted by javap...

In general, you should do whatever's the easiest to read, understand, and modify until profiling has identified some piece of code as a bottleneck.

Jonathan Feinberg
+5  A: 

The key is whether you are writing a single concatenation all in one place or accumulating it over time.

For the example you gave, there's no point in explicitly using StringBuilder. (Look at the compiled code for your first case.)

But if you are building a string e.g. inside a loop, use StringBuilder.

To clarify, assuming that hugeArray contains thousands of strings, code like this:

...
String result = "";
for (String s : hugeArray) {
    result = result + s;
}

is very time- and memory-wasteful compared with:

...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
    sb.append(s);
}
String result = sb.toString();
joel.neely
+8  A: 

I prefer:

String.format( "{a: %s, b: %s, c: %s}", a, b, c );

...because it's short and readable.

I would not optimize this for speed unless you use it inside a loop with a very high repeat count and have measured the performance difference.

I agree, that if you have to output a lot of parameters, this form can get confusing (like one of the comments say). In this case I'd switch to a more readable form (perhaps using ToStringBuilder of apache-commons - taken from the answer of matt b) and ignore performance again.

tangens
It's actually longer, contains more symbols and has variables a text out of sequence.
Tom Hawtin - tackline
So would you say it's less readable than one of the other aproaches?
tangens
I prefer writing this, because it's easier to add more variables, but I'm not sure it's more readable -- especially as the number of arguments gets large. It also doesn't work for times when you need to add bits at different times.
Alex Feinman
Seems harder to read (for me). Now I have to scan back and forth between {...} and the parameters.
Steve Kuo
+15  A: 

Version 1 is preferable because it is shorter and the compiler will in fact turn it into version 2 - no performance difference whatsoever.

More importantly given we have only 3 properties it might not make a difference, but at what point do you switch from concat to builder?

At the point where you're concatenating in a loop - that's usually when the compiler can't substitute StringBuilder by itself.

Michael Borgwardt
That's true but the language reference also states that this is optional. In fact, I just did a simple test with JRE 1.6.0_15 and I didn't see any compiler optimization in the decompiled class.
bruno conde
I Just tried the code from the question (compiled on JDK 1.6.0_16) and found the optimization as expected. I'm pretty sure all modern compilers will do it.
Michael Borgwardt
You are correct. Looking at the bytecode I can clearly see the StringBuilder optimization. I was using a decompiler and, some how, it is converting back to concat. +1
bruno conde
I guess the decompiler tried to be extra smart in restoring the original source code :) I used (a probably old version of) JAD.
Michael Borgwardt
Well I guess this revelation makes my question moot cheers.
non sequitor
+3  A: 

Or, if you don't have time to do your own analysis there is always the internets to help

http://kaioa.com/node/59

reccles
+2  A: 

In most cases, you won't see an actual difference between the two approaches, but it's easy to construct a worst case scenario like this one:

public class Main
{
    public static void main(String[] args)
    {
        long now = System.currentTimeMillis();
        slow();
        System.out.println("slow elapsed " + (System.currentTimeMillis() - now) + " ms");

        now = System.currentTimeMillis();
        fast();
        System.out.println("fast elapsed " + (System.currentTimeMillis() - now) + " ms");
    }

    private static void fast()
    {
        StringBuilder s = new StringBuilder();
        for(int i=0;i<100000;i++)
            s.append("*");      
    }

    private static void slow()
    {
        String s = "";
        for(int i=0;i<100000;i++)
            s+="*";
    }
}

The output is:

slow elapsed 11741 ms
fast elapsed 7 ms

The problem is that to += append to a string reconstructs a new string, so it costs something linear to the length of your strings (sum of both).

So - to your question:

The second approach would be faster, but it's less readable and harder to maintain. As I said, in your specific case you would probably not see the difference.

Omry
Don't forget about .concat(). I would surmise the elapsed time to be anywhere from 10 to 18 ms making it negligible when using short strings like the original post example.
Droo
While you're right about `+=`, the original example was a sequence of `+`, that the compiler transforms to a single `string.concat` call. Your results don't apply.
Blindy
A: 

My rule of thumb (since my .NET days) has been to use StringBuilder for any more than 3 concatenations. Instantiating the StringBuilder (or StringBuffer) object takes time. So it doesn't make sense to me to use it when I'm only concatenating 2 or 3 items.

However, some of these posts make me question this strategy altogether. I didn't realize the compiler was converting this stuff to StringBuilders anyway.

Trevor Allred
A: 

Can I point out that if you're going to iterate over a collection and use StringBuilder, you may want to check out Apache Commons Lang and StringUtils.join() (in different flavours) ?

Regardless of performance, it'll save you having to create StringBuilders and for loops for what seems like the millionth time.

Brian Agnew
+2  A: 

Apache Commons-Lang has a ToStringBuilder class which is super easy to use. It does a nice job of both handling the append-logic as well as formatting of how you want your toString to look.

public void toString() {
     ToStringBuilder tsb =  new ToStringBuilder(this);
     tsb.append("a", a);
     tsb.append("b", b)
     return tsb.toString();
}

Will return output that looks like com.blah.YourClass@abc1321f[a=whatever, b=foo].

Or in a more condensed form using chaining:

public void toString() {
     return new ToStringBuilder(this).append("a", a).append("b", b").toString();
}

Or if you want to use reflection to include every field of the class:

public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

You can also customize the style of the ToString if you want.

matt b
A: 

For simple strings like that I prefer to use

"string".concat("string").concat("string");

In order, I would say the preferred method of constructing a string is using StringBuilder, String#concat(), then the overloaded + operator. StringBuilder is a significant performance increase when working large strings just like using the + operator is a large decrease in performance (exponentially large decrease as the String size increases). The one problem with using .concat() is that it can throw NullPointerExceptions.

Droo
Using concat() is likely to perform worse than '+' since the JLS allows '+' to be converted to a StringBuilder, and most likely all JVM's do so or use a more efficient alternative - the same is not likely to be true of concat which must create and discard at least one complete intermediate string in your example.
Software Monkey
+1  A: 

Make the toString method as readable as you possibly can!

The sole exception for this in my book is if you can prove to me that it consumes significant resources :) (Yes, this means profiling)

Also note that the Java 5 compiler generates faster code than the handwritten "StringBuffer" approach used in earlier versions of Java. If you use "+" this and future enhancements comes for free.

Thorbjørn Ravn Andersen