【问题标题】:String concatenation into StringBuilder java字符串连接到 StringBuilder java
【发布时间】:2011-07-22 18:11:05
【问题描述】:

我有一个遗留的 Java 文件,它使用字符串连接来构建巨大的字符串对象。这是一个严重的性能问题。是否有这样的方法可以执行以下操作

String test="I am a very bad programmer"
+"to use concatenation"
+"Instead of StringBuilder"
+" or StringBuffer";

StringBuilder strBuilder= new StringBuilder();
strBuilder.append("I am a bad programmer");
strBuilder.append("to use concatenation");
strBuilder.append("Instead of StringBuilder");
strBuilder.append(" or StringBuffer");
String str= strBuilder.toString();

基本上我需要一个java中的存根来将String实例化作为输入并转换为StringBuilder。过去有人尝试过吗?

【问题讨论】:

  • AFAIK StringBuilder 和 StringBuffer 仅在循环使用它们时会提高性能,因为编译器会自动将普通连接转换为 StringBuilder(?)。
  • 您确定在其他地方没有性能瓶颈吗?
  • @ZeissS 你应该提供这个作为答案,而不是评论。
  • 感谢您的建议,我们会在需要时继续使用 StringBuilder。
  • @rath:链接的问题不同,因为它不使用 static 字符串。它在连接中使用函数调用。对于 this 问题中的给定示例,我的陈述是正确的。包含函数调用确实会改变情况。

标签: java performance concatenation stringbuilder


【解决方案1】:

只是常量字符串连接在编译时进行了优化,而且是微不足道的。问题是当你做一些不那么琐碎的事情时:

字符串示例1 = "前缀" + 变量字符串1 + "后缀";

最坏的情况是每次迭代都需要创建一个新字符串的循环。由于这对于缓冲读取文件很常见,因此您可以重新创建非常大的字符串,这是我最近遇到的一个问题。

虽然我明白您为什么要做您所做的事情,但代码的结构差异太大,无法直接插入和替换,并且编辑代码的脚本必须非常先进才能处理与所有参考。也许有一种方法可以使用匿名内部类,尽管它可以让您保持相同的字符串引用,但将实际构造包装在字符串构建器中。这可能与优化器已经做的没有什么不同

【讨论】:

    【解决方案2】:

    不,这不是性能问题。例如,如果您要串联字符串内联(就像您展示的那样)而不是使用循环,那么编译器会自动将+ 转换为使用StringBuilder。查看java.lang.String的文档

    Java 语言为字符串连接运算符 ( + ) 以及将其他对象转换为字符串提供了特殊支持。字符串连接是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,由 Object 定义并由 Java 中的所有类继承。有关字符串连接和转换的更多信息,请参阅 Gosling、Joy 和 Steele,Java 语言规范。

    更进一步 - 编译器可能会利用这些都是字符串常量这一事实,甚至在运行时之前加入它们 (JLSreferences)

    【讨论】:

      【解决方案3】:

      在您的示例中使用固定文字比使用 StringBuilder 更有效。

      固定的字面量会被编译器检测到,会被内联为单个值,所以这两行

      String s = "one" + "two" + "three";
      

      String s = "onetwothree";
      

      将生成完全相同的字节码。

      如果连接不是用文字而是用函数调用,情况就不同了。

      当您需要动态附加字符串时,最好使用 StringBuilder 而不是 StringBuffer,因为它不同步,所以速度稍快。

      这是示例字节码:

      公开课测试 { 私有字符串 s = “一”+“二”+“三”; } 公共课Test2 { 私人字符串 s2 = "onetwothree"; }

      为这些类生成的字节码是:

      c:\Temp>javap -c 测试 编译自“Test.java” 公共类测试扩展 java.lang.Object{ 公共测试(); 代码: 0:aload_0 1:调用特殊#1; //方法 java/lang/Object."":()V 4:aload_0 5:最不发达国家#2; //字符串一二三 7:putfield #3; //字段s:Ljava/lang/String; 10:返回 } c:\Temp>javap -c Test2 编译自“Test2.java” 公共类 Test2 扩展 java.lang.Object{ 公共测试2(); 代码: 0:aload_0 1:调用特殊#1; //方法 java/lang/Object."":()V 4:aload_0 5:最不发达国家#2; //字符串一二三 7:putfield #3; //字段s:Ljava/lang/String; 10:返回 }

      如您所见,这两个变量的处理方式相同。

      我认为这不属于语言规范,因为这“只是”一种编译器优化。

      不同的编译器(我使用的是 Sun 编译器)可能会做一些完全不同的事情 - 只要行为没有改变就可以。

      【讨论】:

      • 您能找到该优化的参考吗?这是最明显的事情,但在 JLS 中看到它会很好
      • @bozho:只需创建两个测试类并使用javap -c反编译它们
      • 现在没时间 :) 顺便说一句,javac 还是 eclipse?
      • @Bozho:我添加了一个使用 javac 的示例(我不使用 Eclipse)
      【解决方案4】:

      实际上,编译器已经在最新版本的 Java 中为您应用了该优化(我认为至少从 1.5 开始)。

      What happens when Java Compiler sees many String concatenations in one line?

      http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.18.1.2

      【讨论】:

        猜你喜欢
        • 2010-12-04
        • 2023-03-08
        • 1970-01-01
        • 2014-04-06
        • 2013-03-07
        • 2011-12-26
        • 1970-01-01
        • 2011-12-10
        相关资源
        最近更新 更多