当前位置: 首页 > 知识库问答 >
问题:

编译器何时会选择StringBuffer而不是StringBuilder进行字符串连接

吴驰
2023-03-14

我正在看StringJavadoc,这时我注意到了关于字符串连接的一点:

Java语言为字符串连接运算符()和其他对象到字符串的转换提供了特殊支持。

从Java 8 JLS 15.8.1中,它是编译器的一个选择(我的重点):

实现可以选择在一个步骤中执行转换和级联,以避免创建然后丢弃中间String对象。为了提高重复字符串串联的性能,Java编译器可以使用StringBuffer类或类似的技术来减少通过表达式求值创建的中间字符串对象的数量。

我做了一个小程序,看看它编译成什么

public class Tester {

    public static void main(String[] args) {
        System.out.println("hello");
        for (int i = 1; i < 5; i++) {
            String s = "hi " + i;
            System.out.println(s);
        }
        String t = "me";
        for (int i = 1; i < 5; i++) {
            t += i;
            System.out.println(t);
        }
        System.out.println(t);
    }
}

运行javap-c Tester时的输出显示正在使用StringBuilder

Compiled from "Tester.java"
public class Tester {
  public Tester();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String hello
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: iconst_1
       9: istore_1
      10: iload_1
      11: iconst_5
      12: if_icmpge     48
      15: new           #5                  // class java/lang/StringBuilder
      18: dup
      19: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      22: ldc           #7                  // String hi
      24: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: iload_1
      28: invokevirtual #9                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      31: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: astore_2
      35: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      38: aload_2
      39: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      42: iinc          1, 1
      45: goto          10
      48: ldc           #11                 // String me
      50: astore_1
      51: iconst_1
      52: istore_2
      53: iload_2
      54: iconst_5
      55: if_icmpge     90
      58: new           #5                  // class java/lang/StringBuilder
      61: dup
      62: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      65: aload_1
      66: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      69: iload_2
      70: invokevirtual #9                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      73: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      76: astore_1
      77: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      80: aload_1
      81: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      84: iinc          2, 1
      87: goto          53
      90: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      93: aload_1
      94: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      97: return
}

我看了几个问题,这些问题告诉我们,StringBuilder通常更快,因为在StringBuffer中进行了同步,这可以替代这些字符串连接:

  1. 当StringBuffer/StringBuilder不被编译器隐式使用?
  2. 当Java编译器在一行中看到许多字符串连接时会发生什么?
  3. Java: String conat vs StringBuilder-优化,那么我该怎么办?
  4. 最佳实践/性能:混合StringBuilder.append与String.concat
  5. StringBuilder vsJava中toString()中的String串联
  6. StringBuilder和StringBuffer

因此,考虑到我读到的东西表明,StringBuilder通常是更好的选择,这让我想知道一些事情:

  1. 编译器何时以及为什么会选择使用StringBuffer而不是StringBuilder
  2. 如果编译器可以选择使用任何AbstractStringBuilder实现,这不是更有意义吗

共有2个答案

谢俊英
2023-03-14

这取决于编译器的实现(javac不是唯一的编译器)。然而,对于这些类型的使用,在StringBuilder之上使用StringBuffer从来都不是一个好的例子。在StringBuffer的同步不提供任何功能值的情况下,它始终是一个单一使用的范围很窄的对象

简而言之,没有编译器 /should使用StringBuffer。

司空高义
2023-03-14

您引用的规范措辞源自旧规范。简单的答案是,在Java之前

用Java

从Java开始

 类似资料:
  • 问题内容: 我听说编译器(或者是JVM?)将自动使用StringBuilder进行某些字符串连接。何时才是合适的时间明确声明一个?我不需要StringBuffer来保证线程安全。 谢谢。 问题答案: 编译器将使用“ +”自动将它用于任何字符串连接。 如果要串联连接,通常会显式使用它。例如: 另一种情况是您想在多种方法上构建字符串,或者可能有条件地限制构建的某些位。基本上,如果您不是在单个语句(编译

  • 问题内容: 使用此代码: 当我使用StringBuilder运行代码时,出现错误消息 尝试了StringBuffer,它可以工作。StringBuffer对象的内容被编译为“ Java和Eclipse ..”。 } 问题答案: 确实 有一个接受a 作为参数 的构造函数,并且 确实 有一个方法(由于实现了它必须实现)。 结论:这是您的IDE中的一个不幸,它没有导入正确的。您使用的另一个库具有不幸的“

  • 问题内容: 我最近遇到了一个我以前从未见过的习惯用法:StringWriter和PrintWriter进行的字符串汇编。我的意思是,我知道如何使用它们,但是我一直使用StringBuilder。是否有具体的理由偏爱一个?对我来说,StringBuilder方法似乎更自然,但这只是样式吗? 我在这里查看了几个问题(包括最接近的一个问题:StringWriter或StringBuilder),但没有一

  • 我有一个包含两列的antd表,第一列需要过滤,第二列需要搜索文本。 根据我的代码,应用程序呈现良好。请注意,tags字段是一个json数组,而不是文本字段,所以我想这与错误有关。 更新1代码。 然而,当我添加这一行: 然后我得到这个错误 更新2 这是容器组件

  • 问题内容: 我正在阅读“ 更好,更快,更轻便的Java ”(作者Bruce Tate和Justin Gehtland),并且熟悉敏捷类型团队的可读性要求,例如Robert Martin在其干净的编码书中讨论的内容。在我现在所在的团队中,已明确告知我不要使用运算符,因为它会在运行时创建额外的(和不必要的)字符串对象。 但是,这篇写于‘04的文章讨论了对象分配如何与10条机器指令相关。(基本上免费)

  • 问题内容: 我想知道,由于编译器内部在执行String串联时使用StringBuilder追加字符串,那么有什么意义,如果String串联已经为您完成了工作,为什么还要使用StringBuilder呢?还有其他特定原因吗? 问题答案: 如前所述,您不应使用代替简单的字符串连接表达式,例如。后者的键入速度更快,更易于阅读,并且编译器无论如何都会在内部使用它,因此重写它不会带来性能优势。 但是,如果要