Java5.0 对字符串操作的优化
程序员文章站
2024-01-01 09:38:28
...
最近管理层要求把项目中所有的字符串“+”操作修改为StringBuilder/StringBuffer方式进行操作。以前在java5.0发布的时候好像看到过在这个新的编译器版本中对字符串的操作进行了优化,索性就彻底的研究下。
测试代码
String s1="********";
s1+="--------";
s1+="^^^^^^^^";
StringBuilder s2=new StringBuilder("********");
s2.append("--------");
s2.append("^^^^^^^^");
对应的class文件关键字节码
astore_1 [s1]//s1的是声明
3 new java.lang.StringBuilder [18]//JVM把s1优化为StringBuilder
6 dup
7 aload_1 [s1]
8 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [20]
11 invokespecial java.lang.StringBuilder(java.lang.String) [26]
14 ldc <String "--------"> [29]
16 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [31]//执行“+”操作
19 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [35]//操作完成重新转化为String
22 astore_1 [s1]
23 new java.lang.StringBuilder [18]//再次把string转化为StringBuilder,重新执行上面的步骤
26 dup
27 aload_1 [s1]
28 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [20]
31 invokespecial java.lang.StringBuilder(java.lang.String) [26]
34 ldc <String "^^^^^^^^"> [39]
36 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [31]
39 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [35]
42 astore_1 [s1]
43 new java.lang.StringBuilder [18]//最后转化为StringBuilder ,以备后面可能进行的字符串操作
46 dup
47 ldc <String "********"> [16]//下面是StringBuilder操作方式的字节码,可以看出没有进行String与StringBuilder的相互转化,直接append。
49 invokespecial java.lang.StringBuilder(java.lang.String) [26]
52 astore_2 [s2]
53 aload_2 [s2]
54 ldc <String "--------"> [29]
56 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [31]
59 pop
60 aload_2 [s2]
61 ldc <String "^^^^^^^^"> [39]
63 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [31]
这样基本可以得出结论:在5.0以后的版本,对于String直接进行"+"操作,java编译器会把其优化为StringBuilder后再进行append操作,然后进行来回的String<--->StringBuilder的转化,用StringBuilder的话可以会一直的append直道自己进行StringBuilder--->String的转化,因此在效率上String的“+”操作虽然简洁并比1.4以前的版本中的重新生成String对象进行操作有改进,但效率上仍然与StringBuilder有一定的差距,具体差距有多大,下面随便写了个测试代码
String str1="";
long start=System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
str1+="test";
}
str1+="--------";
long end=System.currentTimeMillis();
System.out.println("String耗时"+(end-start));
//StringBuilder
start=System.currentTimeMillis();
StringBuilder builder=new StringBuilder();
for (int i = 0; i < 50000; i++) {
builder.append("test");
}
builder.append("--------");
builder.toString();
end=System.currentTimeMillis();
System.out.println("StringBuilder耗时"+(end-start));
//随便测试下StringBuffer
start=System.currentTimeMillis();
StringBuffer buffer=new StringBuffer();
for (int i = 0; i < 50000; i++) {
buffer.append("test");
}
buffer.append("--------");
buffer.toString();
end=System.currentTimeMillis();
System.out.println("StringBuffer耗时"+(end-start));
结果:
String耗时7202
StringBuilder耗时16
StringBuffer耗时0
StringBuilder是线程非安全的,StringBuffer是线程安全的,按理来说StringBuilder应该比StringBuffer快才是,但结果有点出乎意料,可能是测试次数少的原因吧,过年了,先写这么多吧。