【问题标题】:Is += more efficient than concat? [duplicate]+= 比 concat 更有效吗? [复制]
【发布时间】:2011-05-18 09:43:20
【问题描述】:

我一直在阅读团队中其他开发人员编写的代码,他们似乎更喜欢使用+= 进行字符串连接,而我更喜欢使用.concat(),因为它更易于阅读。

我试图准备一个论据,说明为什么使用.concat() 更好,我想知道,两者之间的效率有什么区别吗?

我们“应该”采取哪个选项?

public class Stuff {

    public static void main(String[] args) {

        String hello = "hello ";
        hello += "world";
        System.out.println(hello);

        String helloConcat = "hello ".concat("world");
        System.out.println(helloConcat);
    }
}

【问题讨论】:

标签: java string string-concatenation


【解决方案1】:

由于 String 在 java 中是不可变的,所以当您执行 ++=concat(String) 时,会生成一个新的 String。字符串越大,所需的时间就越长——要复制的内容越多,产生的垃圾就越多。

今天的 java 编译器优化了你的字符串连接,使其达到最优,例如

System.out.println("x:"+x+" y:"+y);

编译器将其生成为:

System.out.println((new StringBuilder()).append("x:").append(x).append(" y:").append(y).toString());

我的建议是编写更易于维护和阅读的代码。

此链接显示StringBuilder vs StringBuffer vs String.concat - done right的性能

【讨论】:

    【解决方案2】:

    应该没关系。现代 Java 编译器、JVM 和 JIT 将优化您的代码,使差异可能最小化。您应该努力编写对您来说更具可读性和可维护性的代码。

    【讨论】:

    • 在移动处理器或资源不足的情况下,您会说什么,但这些最小值仍然无关紧要??
    • @Pratik:这些是优化确实很重要的情况。 OP 的问题并未说明需要进行微优化。当然,根据您的环境,您必须小心您正在做的事情。如果你想写一个操作系统,如果你想让它非常快,你就不会用慢的动态语言来做。
    • 我不知道你在想什么优化。
    • @Tom:首先看看@aioobe 的答案。这还不是全部,因为 JIT 可以在运行时进一步优化此代码。具体有哪些优化?这将需要在 JVM 和 JIT 的引擎盖下窥视,所以如果你愿意,你可以这样做。据我了解,它们在过去 15 年中都进行了重大优化,因此它们可能会采取许多技巧来加速一切。
    • @aioobe 的回答实际上表明,看起来非常相似的源代码实际上会生成完全不同的目标代码——这与你所说的相反。真的,没有多少小的字节码——>机器码优化可以用这些不同的代码来做。
    【解决方案3】:

    我同意@darioo 和大多数其他答案。始终将可读性(和可维护性)放在首位。 (现代的 JIT 编译器应该不会遇到像这样的简单情况的问题。)

    然而,这是与您的程序相对应的字节码。 (请注意,+= 方法会产生 StringBuilder,这通常是构造字符串时的首选方法。)

    // String hello = "hello";
    0: ldc #2; //String hello 
    2: astore_1
    
    // hello += "world";
    3: new #3; //class java/lang/StringBuilder
    6: dup
    7: invokespecial #4; //Method StringBuilder."<init>"
    10: aload_1
    11: invokevirtual #5; //Method StringBuilder.append
    14: ldc #6; //String world
    16: invokevirtual #5; //Method StringBuilder.append
    19: invokevirtual #7; //Method StringBuilder.toString
    
    // System.out.println(hello);
    22: astore_1
    23: getstatic #8; //Field System.out
    26: aload_1
    27: invokevirtual #9; //Method PrintStream.println
    
    // String helloConcat = "hello ".concat("world");
    30: ldc #2; //String hello 
    32: ldc #6; //String world
    34: invokevirtual #10; //Method String.concat
    37: astore_2
    
    // System.out.println(helloConcat);
    38: getstatic #8; //Field System.out
    41: aload_2
    42: invokevirtual #9; //Method PrintStream.println
    
    45: return
    

    【讨论】:

      【解决方案4】:

      就可读性而言,我认为你是非常错误的。 + 战胜 .concat()。如果您使用的是+=,您可能需要考虑将StringBuilder.append 保持与循环相同的StringBuilder

      在性能方面concat 优于+。只要你只使用一个或两个。

      concat 的情况下,您最终将创建一个具有正确大小的char[]String 对象。它几乎是您可以获得的最佳效果。

      对于+,javac 生成构造StringBuilder 的代码来执行附加,然后转换为String。从您创建的 1.5 开始:

      • 一个StringBuilder(废物)
      • StringBuilder 的初始 char[](浪费)
      • 如果结果序列太长,则大一秒 char[](浪费)
      • 生成的String
      • Stringchar[]

      但是,您很少看到使用concat,因为它更难阅读。与其他情况相比,性能几乎肯定是沧海一粟(提示:在优化之前先试试信封的背面)。

      【讨论】:

        【解决方案5】:

        你应该做你认为对你来说最短和最清楚的事情。

        但是,为了您的利益。

            String hello = "hello " + "world";
        

        编译将两个String合二为一是最快的。

        这对于两个字符串来说是最快的,因为它避免了创建 StringBuilder。

            String helloConcat = "hello ".concat(world);
        

        但是,如果您有两个以上的字符串使用 StringBuilder,则隐式或显式最快。

        总的来说,我会使用 + ,除非你在循环中使用它,在这种情况下,我可能会显式使用 StringBuilder 来提高性能。

        【讨论】:

        • 没有现代 Java 编译器已经在后台使用 StringBuilder 并且没有区别。
        【解决方案6】:

        concat绝对是两个字符串连接的更快选择,不知道javac内部为什么使用

        (new StringBuilder(String.valueOf(s1))).append(s2).toString()
        

        而不是

        s1.concat(s2)
        

        对于 s1 += s2。查看我对类似问题的回答concatenation operator (+) vs concat()

        【讨论】:

          【解决方案7】:

          我找到了这个artical 并做了这个测试:

          public static void main(String[] args) {
                  String s1 = generateString();
                  String s2 = generateString();
                  String s3 = generateString();
                  String s4 = generateString();
                  String s5 = generateString();
                  String s6 = generateString();
          
                  long e = System.currentTimeMillis();
                  for(int i=0;i<10000000;i++){
                  //StringBuilder > concat> plus >StringBuffer >plusEqual(">"means faster than)
                      //concatPlus(s1 , s2 , s3 , s4 , s5 , s6);//4204ms
                      //concatBuilder(s1 , s2 , s3 , s4 , s5 , s6);//2562ms
                      //concatBuffer(s1 , s2 , s3 , s4 , s5 , s6);//4610ms
                      //concatPlusEqual(s1 , s2 , s3 , s4 , s5 , s6);//9843ms
                      //concatConcat(s1 , s2 , s3 , s4 , s5 , s6);//3036ms
                  }
                  System.out.println(System.currentTimeMillis()-e);           
              }
          
          public static String concatPlusEqual(String s1, String s2, String s3, String s4,
                  String s5, String s6) {
                 String result = "";
                  result += s1;
                  result += s2;
                  result += s3;
                  result += s4;
                  result += s5;
                  result += s6;
                  return result;
          }
          
              public static String concatConcat(String s1, String s2, String s3, String s4,
                      String s5, String s6) {
                  String result = new String();
                  result.concat(s1);
                  result.concat(s2);
                  result.concat(s3);
                  result.concat(s4);
                  result.concat(s5);
                  result.concat(s6);
                  return result;
              }
          
          
              public static String concatBuffer(String s1, String s2, String s3, String s4,
                      String s5, String s6) {
                  return new StringBuffer(s1.length() + s2.length() + s3.length()
                          + s4.length() + s5.length() + s6.length()).append(s1)
                          .append(s2).append(s3).append(s4).append(s5).append(s6)
                          .toString();
              }
          
              public static String concatBuilder(String s1, String s2, String s3, String s4,
                      String s5, String s6) {
                  return new StringBuilder(s1.length() + s2.length() + s3.length()
                          + s4.length() + s5.length() + s6.length()).append(s1)
                          .append(s2).append(s3).append(s4).append(s5).append(s6)
                          .toString();
              }
          
              public static String concatPlus(String s1,String s2,String s3,String s4,String s5,String s6) {
                  return s1 + s2 + s3 + s4 + s5 + s6;
              }
          public static String generateString()
              {
                  Random rng = new Random();
                  int length = 10;
                  String characters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                  char[] text = new char[length];
                  for (int i = 0; i < length; i++)
                  {
                      text[i] = characters.charAt(rng.nextInt(characters.length()));
                  }
                  return new String(text);
              }
          

          看起来 StringBuilder 最快,而 += 最慢。 仅供参考!

          【讨论】:

            猜你喜欢
            • 2012-07-18
            • 2012-01-31
            • 1970-01-01
            • 2012-04-29
            • 1970-01-01
            • 2022-11-23
            • 1970-01-01
            • 2013-03-24
            • 1970-01-01
            相关资源
            最近更新 更多