Java面试汇总中老是会有String,StringBuffer,StringBuilder的区别这种面试题,统一的回答是:
三者连接速度由快到慢:StringBuilder,StringBuffer,String
StringBuilder非线程安全,StringBuffer线程安全
String是字符串常量,二StringBuilder和StringBuffer为字符串变量,也就是说String一旦创建就不可更改,每次做连接操作时实际上又重新创建了一个String,然后将拼接后的结果存储在这个新的string对象指向的地址里,由于不断创建新的String对象导致了连接速度大大降低,而StringBuffer和StringBuilder则是直接在字符串变量后进行连接操作,速度才会明显快于String。
至于StringBuffer线程安全则是由于StringBuffer中的大部分方法都被synchronized(关于synchronized关键字本人之前的博客有介绍,感兴趣可以。。。嘿嘿嘿)修饰,简单来说就是实现了同步机制,导致了速度慢于StringBuilder
那么真实的场景下到底结果如何呢?让我们来梭哈一段代码测试一下
public class StringBuliderBuffer {
private static StringBuilder sbu=new StringBuilder("a");
private static StringBuffer sbf=new StringBuffer("a");
private static String str=new String("a");
private static long count=1000;
public static void main(String[] args) {
long startSbuTime=System.currentTimeMillis();
for (long i = 0; i < count; i++) {
sbf.append(i);
}
long endSbuTime=System.currentTimeMillis();
System.out.println("StringBuffer运行时间:"+(endSbuTime-startSbuTime));
startSbuTime=System.currentTimeMillis();
for (long i = 0; i < count; i++) {
sbu.append(i);
}
endSbuTime=System.currentTimeMillis();
System.out.println("StringBuilder运行时间:"+(endSbuTime-startSbuTime));
startSbuTime=System.currentTimeMillis();
for (long i = 0; i < count; i++) {
str=str+i;
}
endSbuTime=System.currentTimeMillis();
System.out.println("String运行时间:"+(endSbuTime-startSbuTime));
}
}
分别创建了各自的对象,并且初始化,然后测试执行循环连接,测试连接前后的时间差,结果如下
次数count=1000时
StringBuffer运行时间:1
StringBuilder运行时间:0
String运行时间:3
次数count=100000
StringBuffer运行时间:16
StringBuilder运行时间:0
String运行时间:22418
次数count=1000000
StringBuffer运行时间:78
StringBuilder运行时间:31
次数为1000次时,结果不明显
十万次时结果已经比较明显,StringBuilder的时间仍未0(这个有点诡异),而String时间明显与其它俩天壤之别
一百万次时StringBuilder和StringBuffer差距拉开,总得来说仍在同一个等级上,而String结果仍未完成(此时已等待了10分钟,我洗好了衣服回来仍未结束)
所以应尽少使用String的拼接操作,但是在内存中已经有拼接后的字符串这种情况时,String的速度快于其它两者,可能因为拼接后的字符串如果已经存在,String不会再做拼接操作,而是将当前字符串指向已有字符串的地址,所以速度很快
至于StringBuffer和StringBuilder的选择,由于时间差不多,所以一般选择线程安全的StringBuffer