long startTime = System.currentTimeMillis();
String aaa = "aaa";
String ccc = "ccc";
String ddd = "ddd";
String eee = "ddd";
String fff = "ddd";
String ggg = "ddd";
String hhh = "ddd";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000000; i++) {
sb.append(aaa);
sb.append("accc");
sb.append(ccc);
sb.append("vvvc");
sb.append(ddd);
sb.append(eee);
sb.append(fff);
sb.append(ggg);
sb.append(hhh);
sb.delete(0, sb.length());
}
//1.................
System.out.println(System.currentTimeMillis() - startTime);

try {
Thread.sleep(1000);
}
catch (InterruptedException e1) {
e1.printStackTrace();
}
startTime = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
String acc = aaa+"accc"+ccc+"vvvc"+ddd+eee+fff+ggg+hhh;
}
//2.................
System.out.println(System.currentTimeMillis() - startTime);

startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
String add = "a";
for (int j = 0; j < 1000; j++) {
add += aaa;
}
}
//3.................
System.out.println(System.currentTimeMillis() - startTime);
测试之后结果很明显:
1 和 2时间差不多. 1显得稍微高效一点. 
  -- 但是你别忘记了,很多时候你都是new的StringBuilder对象而不是 写StringBuilder.delete 进行重复使用.
如果把new StringBuilder 的代码换到循环体里面,你会发现  StringBuilder 的效率还不如 String = +..+..+3的时间花费令人叹服. -- 太慢了.
这也是传统意义上不停有人叫嚷  别用 String 拼接字符串 要使用 StringBuilder 的最根本性原因.
但是你有没有发现他的独特性?  ---> '+='总结一下吧:
1,如果你的需求仅仅是:  String = int变量+"ccc"+String变量+String变量+String变量 的话;  那么,不要使用StringBuilder 
  -- 你是不是经常看见 有人在拼接一个明显不需要for循环的 url 的时候 采取StringBuilder 方式,并且还是和new的StringBuilder临时变量?
  -- 你是不是经常看见 有人在拼接一个明显不需要for循环的 log 输出字符串的时候 采取StringBuilder 方式?
2,如果你要用一个for循环来拼接一个 String 的话. 那么,不要使用String ;3,出于线程并发考虑,我同时也不推荐使用StringBuilder作为全局变量.

解决方案 »

  1.   

    1 基本没看见过你说的这情况,我都是String直接拼
      

  2.   

    特地跑去找了些东西
    Optimization of String Concatenation An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class (§20.13) or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression. String的+本来就是用StringBuilder(JDK 5或以上)或StringBuffer(JDK 1.4或以下)实现的。 
    关键问题是:是不是同一个StringBuilder/StringBuffer。在循环里用+=之类的方式来拼接字符串的问题就出在每轮循环里都new了一个StringBuilder/StringBuffer来做拼接,然后toString()完就抛弃了,等下轮循环进来又再new一个。 以上全部从RednaxelaFX博客里面翻出来的东西
    http://rednaxelafx.iteye.com/blog/1042464
    神不神话什么的完全看你怎么用.
      

  3.   

    public class Example {
        public static void main(String[] args) {
            String aaa = "aaa";
            String ccc = "ccc";
            String ddd = "ddd";
            String eee = "ddd";
            String fff = "ddd";
            String ggg = "ddd";
            String hhh = "ddd";
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 10000000; i++) {
                String acc = aaa+"accc"+ccc+"vvvc"+ddd+eee+fff+ggg+hhh;
            }
            System.out.println(System.currentTimeMillis() - startTime);               
        }
    }
    看清楚
    javap -c Example 
    Compiled from "Example.java"
    public class Example {
      public Example();
        Code:
           0: aload_0       
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return          public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String aaa
           2: astore_1      
           3: ldc           #3                  // String ccc
           5: astore_2      
           6: ldc           #4                  // String ddd
           8: astore_3      
           9: ldc           #4                  // String ddd
          11: astore        4
          13: ldc           #4                  // String ddd
          15: astore        5
          17: ldc           #4                  // String ddd
          19: astore        6
          21: ldc           #4                  // String ddd
          23: astore        7
          25: invokestatic  #5                  // Method java/lang/System.currentTimeMillis:()J
          28: lstore        8
          30: iconst_0      
          31: istore        10
          33: iload         10
          35: ldc           #6                  // int 10000000
          37: if_icmpge     100
          40: new           #7                  // class java/lang/StringBuilder
          43: dup           
          44: invokespecial #8                  // Method java/lang/StringBuilder."<init>":()V
          47: aload_1       
          48: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          51: ldc           #10                 // String accc
          53: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          56: aload_2       
          57: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          60: ldc           #11                 // String vvvc
          62: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          65: aload_3       
          66: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          69: aload         4
          71: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          74: aload         5
          76: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          79: aload         6
          81: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          84: aload         7
          86: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          89: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
          92: astore        11
          94: iinc          10, 1
          97: goto          33
         100: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         103: invokestatic  #5                  // Method java/lang/System.currentTimeMillis:()J
         106: lload         8
         108: lsub          
         109: invokevirtual #14                 // Method java/io/PrintStream.println:(J)V
         112: return        
    }
      

  4.   

    我不知你是怎么测试的,3种代码,我分开测试,每种跑6次,我贴一下我机器上的时间:
    第一种,用StringBuilder:(将StringBuilder对象在循环外声明,然后delete)
                1882、1860、1952、1949、1953、1946
            用Stringbuilder:(将StringBuilder对象在循环内声明)
                3814、3795、4137、3940、4117、3965
    第二种,用+:
                3932、4034、4051、4023、4008、4035
    第三种,你那个写法用的时间和前两种不是一个数量级上的,要慢很多,但是你这种测试代码和之前的没比较性,我觉得应该这么写:        for (int i = 0; i < 10000; i++) {            
                for (int j = 0; j < 1000; j++) {
                    String add = "a"; //把这个add放在这个循环内,才能表现出创建100000000次
                    add += aaa;
                }
            }
    关于你的:
    “1 和 2时间差不多. 1显得稍微高效一点. ”
      2的时间可是1的一倍,怎么是差不多呢?-------------------------------------------------------* “如果把new StringBuilder 的代码换到循环体里面,你会发现 StringBuilder 的效率还不如 String = +..+..+”
      测试时间我已经贴出来了,几乎是一样的。String的+在JAVA5及其之后在编译时就优化成了StringBuilder.append(), 然后 StringBuilder.toString(); JAVA5之前用的是StringBuffer,
    两种一样的代码,为什么你的结论会是StringBuilder的效率还不如+呢?------------------------------------------------------------*“3的时间花费令人叹服. -- 太慢了.这也是传统意义上不停有人叫嚷 别用 String 拼接字符串 要使用 StringBuilder 的最根本性原因.
    但是你有没有发现他的独特性? ---> '+='”

      首先你的测试代码就有问题,其次String的 +=的独特性在什么地方?不管是用+还是+=,只要不是编译时常量,编译的时候都会用StringBuilder来优化。你的总结都没问题,但是你的测试有问题,为什么结论是正确的,有点搞不懂了 :)
    总结第三点:不推荐StringBuilder是因为StringBuilder是不支持并发的,StringBuffer却是支持的。可以使用StringBuffer。
      

  5.   

    NND,应该占个沙发在回帖的,噼里啪啦的跑一通,打一堆,最后连沙发都没了
      

  6.   

    上面是5,6,7的结果。
    这个是1.4的结果:
    javap -c Example
    Compiled from "Example.java"
    public class Example {
      public Example();
        Code:
           0: aload_0       
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return          public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String aaa
           2: astore_1      
           3: ldc           #3                  // String ccc
           5: astore_2      
           6: ldc           #4                  // String ddd
           8: astore_3      
           9: ldc           #4                  // String ddd
          11: astore        4
          13: ldc           #4                  // String ddd
          15: astore        5
          17: ldc           #4                  // String ddd
          19: astore        6
          21: ldc           #4                  // String ddd
          23: astore        7
          25: invokestatic  #5                  // Method java/lang/System.currentTimeMillis:()J
          28: lstore        8
          30: iconst_0      
          31: istore        10
          33: iload         10
          35: ldc           #6                  // int 10000000
          37: if_icmpge     100
          40: new           #7                  // class java/lang/StringBuffer
          43: dup           
          44: invokespecial #8                  // Method java/lang/StringBuffer."<init>":()V
          47: aload_1       
          48: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          51: ldc           #10                 // String accc
          53: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          56: aload_2       
          57: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          60: ldc           #11                 // String vvvc
          62: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          65: aload_3       
          66: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          69: aload         4
          71: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          74: aload         5
          76: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          79: aload         6
          81: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          84: aload         7
          86: invokevirtual #9                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
          89: invokevirtual #12                 // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
          92: astore        11
          94: iinc          10, 1
          97: goto          33
         100: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         103: invokestatic  #5                  // Method java/lang/System.currentTimeMillis:()J
         106: lload         8
         108: lsub          
         109: invokevirtual #14                 // Method java/io/PrintStream.println:(J)V
         112: return        
    }
      

  7.   

    我在最后一行又加了个System.out.println("test end");然后再这行打了断点. 测试结果如下
    3703
    3344
    29375把断点删除. 测试结果如下
    1328
    1734
    28282断点打在 执行代码之外 也有这么大的影响.....
      

  8.   

    StringBuilder 对于+的优化并不在于时间, 而在于空间, 对于+ 如下代码会生成5个String常量String a = "aaa";  // 1
    String b = "bbb";  // 2
    String c = "ccc";  // 3
    String d = a+b+c;  // "aaabbb" 4 "aaabbbccc" 5而StringBuilder就只会生成4个常量,不会有中间的"aaabbb"生成。 
    如果这种相加有很多,就会有很多很多额外的空间被占用,对内存是很大的浪费。