引言:
关于String,StringBuilder,StringBuffer的问题,在日常开发中似乎并没有引起我们的重视,但是仅仅这个点可能就影响到我们编写的程序的性能,同时这个点也是面试时经常被问到的java基础题。下面我们从理论和实践2个方面来分析和论证3者之间的关系。
一.理论
String,StringBuffer,StringBuilder比较
string | 字符常量,是属于不可变类,任何对String的修改都会引发新的string对象生成 |
stringBuffer | 字符变量,线程安全,支持并发操作,单线程下效率比StringBuilder低 |
stringBuilder | 字符变量,线程不安全,不支持并发操作,不考虑多线程情况下,推荐使用这种方式 |
二.实践
1. string本质
String s="abc";
s=s+"d";
System.out.println(s);
前面我们提到String是“字符创常量”,也就是不可改变的对象,在上面代码中我们明明就是改变了String型的变量s的,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多底。
2.String,StringBuffer,StringBuilder执行速度差异
package test;
import org.junit.Test;
public class StringTest {
public String testcontent="welcome to my blog";
public int testCount=100000;
//string测试
public void Stringtest(){
long start=System.currentTimeMillis();
String s="";
for(int i=0;i<=testCount/10;i++)
{
s=s+testcontent;
}
long end=System.currentTimeMillis();
long time=end-start;
System.out.println("string:"+time+" millis");
}
//stringbuffer测试
public void StringBuffertest(){
StringBuffer s=new StringBuffer();
long start=System.currentTimeMillis();
for(int i=0;i<=testCount;i++)
{
s.append(testcontent);
}
long end=System.currentTimeMillis();
long time=end-start;
System.out.println("stringBuffer:"+time+" millis");
}
//stringbuilder测试
public void StringBuildertest(){
StringBuilder s=new StringBuilder();
long start=System.currentTimeMillis();
for(int i=0;i<=testCount;i++)
{
s.append(testcontent);
}
long end=System.currentTimeMillis();
long time=end-start;
System.out.println("stringBuilder:"+time+" millis");
}
}
执行结果如下:
stringbuilder:15millis
stringbuffer:16millis
string:1692 millis
三,结论
1.速度比较
三者在执行速度方面的比较:StringBuilder > StringBuffer > String
2.应用场景
String | 当操作小数据集的字符时可以考虑使用 |
StringBuffer | 当在多线程环境下建议使用 |
StringBuilder | 在单线程下,操作大字符串时,或者涉及字符串多次修改,变更操作时使用(推荐) |