【问题标题】:Why use StringBuilder explicitly if the compiler converts string concatenation to a StringBuilder automatically? [duplicate]如果编译器自动将字符串连接转换为 StringBuilder,为什么要显式使用 StringBuilder? [复制]
【发布时间】:2012-08-10 03:48:05
【问题描述】:

可能重复:
StringBuilder vs String concatenation in toString() in Java

我想知道,由于编译器在执行字符串连接时在内部使用 StringBuilder 来附加字符串,那么如果字符串连接已经为您完成了这项工作,那么有什么意义?为什么还要使用 StringBuilder 呢?还有其他具体原因吗?

【问题讨论】:

    标签: java stringbuilder


    【解决方案1】:

    正如您所提到的,您不应使用StringBuilder 而不是简单的字符串连接表达式,例如a + " = " + b。后者打字速度更快,更容易阅读,而且编译器无论如何都会在内部使用StringBuilder,因此重写它并没有性能优势。

    但是,如果您在循环中连接大量字符串,StringBuilder 会很有用。以下代码效率低下。它需要 O(n2) 时间来运行并创建许多临时字符串。

    String result = "";
    for (int i = 0; i < foo.length; ++i)
    {
        result += bar(foo[i]);  // Bad
    }
    

    试试这个:

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < foo.length; ++i)
    {
        sb.append(bar(foo[i]));
    }
    String result = sb.toString();
    

    编译器只优化简单的a + b + c 表达式。无法自动优化上述代码。

    【讨论】:

    • @JohanSjöberg 是的,事实上确实如此。执行result += bar(foo[i]) 将产生类似(假设javac)result = new StringBuilder().append(result).append(foo[i]).toString() 的代码。请注意,这比使用 StringBuilder 要多得多。
    • @user1389813:这是因为在第一个示例中,Java 的优化器不知道如何保留一个 StringBuilder 来完成循环中的所有连接——它看不到足够远的距离来了解你' 将始终连接到相同的字符串,否则永远不会看到循环的外部,因此每次它必须添加到 result 时都会创建一个新字符串。
    • @user1389813 using += 将在每次迭代中创建一个新的StringBuilder,复制源字符串,附加您要连接的任何内容(这也可能需要一个副本),然后将其转换为String(这是另一个副本)。使用一个StringBuilder 可以避免不必要的复制。
    • 结果 = 结果 + bar(foo[i]); ?是不是也是一样的结局?
    • @cHao 是的,我完全了解理论——但我正在讨论手头的实际编译器(假设它是 javac)。 javac 不再显式地执行任何真正的 优化,而且它从未做过那么复杂的优化。它所做的就是不断折叠和 DCE 通行证。
    【解决方案2】:

    您在哪里假设字符串连接在内部使用 stringbuilder ?也许一个简单的 concat 会被优化掉,但这绝对不会:

    String s = "";
    
    for (int i = 0; i < 1000; i++){
      for (int j = 0; j < 1000; j++){
        s+= "" + i + j
    }
    }
    

    【讨论】:

    • 那么内部会是什么?
    • @user1389813 s = new StringBuilder.append("").append(i).append(j).toString(); 假设编译器是 javac。
    • 所以每次它都会创建一个新的 StringBuilder 来执行连接,所以这就是为什么它很糟糕而且很慢,对吗?
    • 我不会说它一定是(我不提倡过早优化)......这不是一个好习惯。
    • @user1389813 不仅仅是创建了一个新的StringBuilder,而是创建了一个新的StringBuilder,然后从s字符串中复制了所有的字符,只有then 附加 ij。每个循环,您都在复制您之前拥有的所有字符(它们本身是从之前的循环中复制的),从而为您提供 O(n^2) 性能。通过从循环体中删除新的 StringBuilder,您可以消除所有多余的复制。
    猜你喜欢
    • 2012-02-25
    • 2011-12-26
    • 2011-07-11
    • 1970-01-01
    • 2011-06-19
    • 2013-03-07
    • 2020-09-28
    • 2013-12-13
    相关资源
    最近更新 更多