package org.wsy.javase.com.hspedu.Stringbuilder_;
/**
* @author Sakura
* @copyright Sakura
*/
public class StringVsStringBufferVsStringBuilder {
public static void main(String[] args) {
int num = 800000;
long startTime = 0L;
long endTime = 0L;
StringBuffer stringBuffer = new StringBuffer("");
startTime = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
stringBuffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer:" + (endTime - startTime));
StringBuilder stringBuilder = new StringBuilder("");
startTime = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
stringBuilder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder:" + (endTime - startTime));
String string = "";
startTime = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
string += string + i;
}
endTime = System.currentTimeMillis();
System.out.println("String:" + (endTime - startTime));
}
}
运行结果:当运行到String拼接的时候,直接抛出异常,OutOfMemoryError,严重错误,直接奔溃
StringBuffer很多方法都是由synchronized修饰的,所以它是线程安全的
得出结论:
如果字符串存在大量修改操作,一般使用StringBuffer和StringBuilder,如果是单线程则使用StringBuilder,多线程使用StringBuffer
如果字符串很少修改,被多个对象引用,一般使用String
StringBuffer和String进行转换的时候出现的问题:当String = null的时候,两种方式转化结果大不相同
//方式 1 使用构造器
StringBuffer stringBuffer = new StringBuffer(str);
//方式 2 使用的是 append 方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
System.out.println(sb.length());
System.out.println(sb);
StringBuffer sb1 = new StringBuffer(str);
System.out.println(sb1);
结果:
使用append方法sb的长度为4,内容为null,而使用构造器的方式会直接抛出空指针异常,我看了下源码:
原来在使用append方法的时候会调用父类AbstractStringBuilder中的append方法,当传入的参数为null时,直接返回一个appendNull方法返回的结果,会把“null”放到自己的char类型的value数组中,注意这个value数组不是final修饰的,说明使用时不用每次都更换地址(即不是每次创建新对象), 所以效率高于 String
这就证明了为什么输出结果是4 和 null
我又看了通过构造器的方式创建Stringbuffer对象的源码:
这个会先调用父类构造器,传入该字符串序列的长度+16的int类型的参数,由于该字符串序列是null,所以会抛出空指针异常。