最后看concat3,for循环中使用字符串连接,最后在for循环外使用连接后的字符串。字节码中的[11,29]之间是循环体,很容易发现,循环体中做了new StringBuilder的操作,字节码代表的代码含义如下:
| String s3 = ""; for(int i=0; i<100; i++) { s3 = new StringBuilder().append(s3).append(i).toString(); } |
在这种情况下,编译器的优化并不如我们的意,我们想要的优化代码是这样的:
| String s3 = ""; StringBuilder tmp = new StringBuilder(); tmp.append(s3); for(int i=0; i<100; i++) { tmp.append(i); } s3 = tmp.toString(); |
这对于编译器来说有些复杂了,我们需要手工才能做到。
综上三个方法的分析发现,用StringBuilder(StringBuffer)#append替代字符串”+”是否会带来性能提升并不是一成不变的,在不同的条件下情况也不相同,字符串字面值的连接在编译期间已经连接好了,普通的字符串连接并不需要显式的使用new StringBuilder().append来增加效率,编译器已经给我们做掉了,除非能在显式使用时能给出有效的初始容量。在这种意义下,个人觉得string的”+”可以认为是StringBuilder#append的一个语法糖;但是如果形如concat3那种循环中的字符串连接,我们就需要显式使用StringBuilder了。在jdk1.4的时候,还没有StringBuilder类,编译器生成的优化代码使用的是StringBuffer。
针对String连接操作编译器生成的StringBuidler#append肯定是单个线程在操作,因此不会有线程安全问题。