先前看到论坛中有人说JDK5下,String的连加操作会被JVM优化为StringBuffer.append()操作,因此拼装String时,两者的性能是一样的。今天闲着没事,写了段小程序测试了一下,对字母A进行1100次拼接,发现StringBuffer的性能比String连加要高出将近100倍,不知是怎么回事。各位给看看,附件是我的测试程序。
JVM优化是对的,我这里没有JDK5.0.用的是6.0测试的,6.0对于String的连加采用的是StringBuilder优化的,按说优化了为什么StringBuffer的性能还是那么好呢。下面就分析一下。测试用例如下:
[code="java"]/**
@since 2010-7-10
*/
public class TestStringBuffer {
public void testString(){
String s="";
for(int i=0;i<10000;i++){
s+=i;
}
}
public void testStringBuffer(){
StringBuffer s=new StringBuffer("");
for(int i=0;i<10000;i++){
s.append(i);
}
}
}[/code]
这两个函数分别演示了string的连加和StringBuffer操作,执行测试,我本机上testString()600多毫秒,testStringBuffer()不超过20毫秒。下面就分析为什么,我们采用JDK的反汇编工具javap,执行javap -c TestStringBuffer后我们看到CMD输出,我们挑重要的看,先看方法testString。
[code="java"]public void testString();
Code:
0: ldc #19; //String
2: astore_1
3: iconst_0
4: istore_2
5: goto 30
8: new #21; //class java/lang/StringBuilder
11: dup
12: aload_1
13: invokestatic #23; //Method java/lang/String.valueOf:(Ljava/lang/Objec
t;)Ljava/lang/String;
16: invokespecial #29; //Method java/lang/StringBuilder."":(Ljava/la
ng/String;)V
19: iload_2
20: invokevirtual #32; //Method java/lang/StringBuilder.append:(I)Ljava/la
ng/StringBuilder;
23: invokevirtual #36; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
26: astore_1
27: iinc 2, 1
30: iload_2
31: sipush 10000
34: if_icmplt 8
37: return[/code]
我就不一行行分析了,有兴趣的可以看看相关知识,分析关键的,循环从“2:”开始到“34:”看第“8:”,创建了一个StringBuilder,然后使用append方法("第20:")进行String连加的优化,最要注意的是 创建这个StringBuilder,是在循环里面,也就是说我们循环多少次就会创建多少个StringBuilder,这就很影响性能(创建对象是很耗性能的).然后我们看testStringBuffer方法。
[code="java"]public void testStringBuffer();
Code:
0: new #46; //class java/lang/StringBuffer
3: dup
4: ldc #19; //String
6: invokespecial #48; //Method java/lang/StringBuffer."":(Ljava/lan
g/String;)V
9: astore_1
10: iconst_0
11: istore_2
12: goto 24
15: aload_1
16: iload_2
17: invokevirtual #49; //Method java/lang/StringBuffer.append:(I)Ljava/lan
g/StringBuffer;
20: pop
21: iinc 2, 1
24: iload_2
25: sipush 10000
28: if_icmplt 15
31: return[/code]
看看多么简单,在循环开始前创建好StringBuffer,然后再循环里面调用append方法(第17:),只创建了一个对象,然后只在缓冲区里面进行字符操作。
没有看到附件,如果直接用String,至少jdk还要帮你重新实例化一下了,用stringbuffer就直接操作了
其实,我更想问的是,为啥之前你不用循环
在字符串修改操作频繁的情况下, 肯定是 StringBuffer 的性能优于 String 的性能.
StringBuffer 出现的目的就是为了改进 String 的缺点
只不过 StringBuffer 是线程安全的, 它会在线程控制方面额外用力, 如果是单线程环境下频繁操作字符串, 可以使用 StringBuilder
粘贴,复制的大神
为啥你那么纠结性能?既然你知道StringBuffer 和 String 在处理不同问题上的优点.为啥你还要去关注性能呢?不解!
[quote]这个我知道,我想问的是,之前别的帖子上说,JDK5下JVM会将String连加优化为StringBuilder.append()操作,这样的话,上面的测试中,两者的耗时应该是很接近的,但实际却不是这样,不解。 [/quote]
他这么说有给出他的依据么? 这个可以咨询他一下的.
但是据我查看 JDK 5 的 changenote, 是没有提到 String 的这一优化方式的.
[url]http://java.sun.com/j2se/1.5.0/ReleaseNotes.html#intro[/url]
很明显这位大神在浪费时间。。。
如果官方没有文档的话,
1) 可以咨询这个讨论主题里提出这个观点的人
2) 搜索相关主题
因为在这里, 很难遇到对这个在官方文档都没有提及的问题有深入了解的人
拜求,String的连加优越在哪?
你在看一下,别的帖子说的String连加会不会是
aa="A"+"A"+"A"+"A"+"A"+"A"+"A"+"A"+"A"+"A"+"A"+"A"
而不是
aa += "A";aa += "A";aa += "A";aa += "A";aa += "A";
我记得当时我侧过10w循环的测试
String 和StringBuffer 时间没有任何差别!!
我不知道你是怎么测得啊
http://www.javaworld.com/javaworld/javatips/jw-javatip92.html