代码实现
String 类是一个final类型的不可变类,所以在对String类进行操作时,都会创建一个新的String类,造成空间和时间的开销。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
}
StringBuilder类 和StringBuffer类均实现了相同的接口和继承了相同的父类,只是StringBuffer的方法上加了synchronized关键字,保证在多线程情况下是线程安全的,其它实现没有差别。
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(int i) {
super.append(i);
return this;
}
}
StringBuffer类
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{
@Override
@HotSpotIntrinsicCandidate
public synchronized StringBuffer append(int i) {
toStringCache = null;
super.append(i);
return this;
}
}
性能对比
通过写代码对比,String的性能比StringBuffer和StringBuiler慢5-10个数量级;
在单线程情况下,StringBuffer的性能反而比StringBuilder快,具体原因有待分析;
在多线程情况下,StringBuilder性能比StringBuffer性能快,因为StringBuffer需要获取对象锁;
测试结果为:
StringBuilder cost:14
MultiStringBuffer cost:102
MultiStringBuilder cost:61
StringBuffer cost:9
String cost:940
@TestInstance(Lifecycle.PER_CLASS)
public class GenericTest {
@Test
public void testString() {
AtomicReference<String> s = new AtomicReference<>("");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
IntStream.range(0, 100000).forEach(i -> {
s.set(s + "i");
});
stopWatch.stop();
System.out.println("String cost:" + stopWatch.getTotalTimeMillis());
}
@Test
public void testStringBuilder() {
StringBuilder s = new StringBuilder();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
IntStream.range(0, 100000).forEach(i -> {
s.append(i);
});
stopWatch.stop();
System.out.println("StringBuilder cost:" + stopWatch.getTotalTimeMillis());
}
@Test
public void testStringBuffer() {
StringBuffer s = new StringBuffer();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
IntStream.range(0, 100000).forEach(i -> {
s.append(i);
});
stopWatch.stop();
System.out.println("StringBuffer cost:" + stopWatch.getTotalTimeMillis());
}
@Test
public void testMultiStringBuilder() throws InterruptedException {
StringBuilder s = new StringBuilder();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Thread t1 = new Thread(() -> {
IntStream.range(0, 100000).forEach(i -> {
s.append(i);
});
});
Thread t2 = new Thread(() -> {
IntStream.range(0, 100000).forEach(i -> {
s.append(i);
});
});
t1.start();
t2.start();
t1.join();
t2.join();
stopWatch.stop();
System.out.println("MultiStringBuilder cost:" + stopWatch.getTotalTimeMillis());
}
@Test
public void testMultiStringBuffer() throws InterruptedException {
StringBuffer s = new StringBuffer();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Thread t1 = new Thread(() -> {
IntStream.range(0, 100000).forEach(i -> {
s.append(i);
});
});
Thread t2 = new Thread(() -> {
IntStream.range(0, 100000).forEach(i -> {
s.append(i);
});
});
t1.start();
t2.start();
t1.join();
t2.join();
stopWatch.stop();
System.out.println("MultiStringBuffer cost:" + stopWatch.getTotalTimeMillis());
}
}
应用场景
对于少量的字符串拼接,可以采用String;
对于单线程下大量字符串操作,用StringBuffer和StringBuilder均可;
对于多线程下的大量字符串操作,采用StringBuffer;