给定下面的2个toString()实现,哪个是首选的:

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();
}

?

更重要的是,鉴于我们只有3个属性,它可能不会有什么不同,但在什么时候你会从+ concat切换到StringBuilder?


当前回答

我认为这张图对于比较所有使用string的类非常有用:

其他回答

我认为我们应该使用StringBuilder附加方法。 原因是:

String连接每次都会创建一个新的String对象(因为String是不可变对象),所以它将创建3个对象。 使用String生成器只会创建一个对象[StringBuilder is mutable],并且进一步的字符串被追加到它。

我喜欢:

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

...因为它简短易读。

我不会为速度而优化它,除非您在重复次数非常高的循环中使用它,并测量了性能差异。

我同意,如果必须输出大量参数,这个表单可能会令人困惑(就像其中一个评论所说的那样)。在这种情况下,我将切换到更可读的形式(可能使用apache-commons的ToStringBuilder -取自matt b的答案),并再次忽略性能。

使用'+'的字符串连接的性能更昂贵,因为它必须创建一个全新的字符串副本,因为字符串在java中是不可变的。如果连接非常频繁,例如:在循环中,这将发挥特别的作用。 以下是我的想法,当我试图做这样的事情:

一般规则:

在单个字符串赋值中,使用字符串连接是很好的。 如果您正在循环构建一个大的字符数据块,请使用StringBuffer。 在String上使用+=总是比使用StringBuffer效率低,所以它应该敲响警钟——但在某些情况下,所获得的优化与可读性问题相比微不足道,所以使用你的常识。

这里有一篇关于这个话题的Jon Skeet博客。

在大多数情况下,你不会看到这两种方法之间的实际区别,但很容易构建一个像下面这样的最坏情况:

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+="*";
    }
}

输出结果为:

slow elapsed 11741 ms
fast elapsed 7 ms

问题是,+=追加到一个字符串重构一个新的字符串,所以它的代价是字符串长度的线性(两者的和)。

对于你的问题

第二种方法更快,但可读性较差,也更难维护。 正如我所说,在你的具体情况下,你可能看不到区别。

我认为这张图对于比较所有使用string的类非常有用: