String、StringBuffer、StringBuilder的比较

本文对比了Java中的String、StringBuffer和StringBuilder。String是不可变的,每次修改都会创建新对象;StringBuffer和StringBuilder是可变的,适合字符串拼接,其中StringBuffer是线程安全的,StringBuilder则不是。在单线程环境下,StringBuilder的性能优于StringBuffer。预先指定容量可以提高执行效率。适用场景:String用于不变字符串,StringBuffer在多线程拼接时,StringBuilder用于单线程字符串操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、String

String是不可变的字符串,比如字符串string="abc",在是如果想改变字符串的值,string = "def",JVM会生成新的字符串"def",而不是在原来的字符串上改,原来的字符串"abc"会被垃圾回收器收回。

2、StingBuffer

StringBuffer是可变的字符串,如果修改StringBuffer的值,是直接在原来的字符串上修改。

StringBuffer是线程安全的。

3、StringBuilder

StringBuffer是可变的字符串,如果修改StringBuffer的值,是直接在原来的字符串上修改。

StringBuffer不是线程安全的。

4、三者比对

在字符串拼接的过程中,三者的效率最高是StringBuilder,其次是StringBuffer,最后是String。

我们来看一下程序实际运行的情况

public class StringTest {
	public static void main(String[] args) {
		String value = "1234567890";
		int count = 30000;		
		System.out.println("String     StringBuffer     StringBuilder");
		for (int j = 1; j <= 10; j++) {
			String string = "";
			StringBuffer stringBuffer = new StringBuffer();
			StringBuilder stringBuilder = new StringBuilder();
			long begin = System.currentTimeMillis();
			for (int i = 0; i < count; i++) {
				string = string + value;
			}
			
			long end1 = System.currentTimeMillis();
			System.out.print((end1 - begin) + "毫秒                        ");
			
			for (int i = 0; i < count; i++) {
				stringBuffer.append(value);
			}
			
			long end2 = System.currentTimeMillis();
			System.out.print((end2 - end1) + "毫秒                        ");
			
			for (int i = 0; i < count; i++) {
				stringBuilder.append(value);
			}
			long end3 = System.currentTimeMillis();
			System.out.println((end3 - end2) + "毫秒");
		}
	}
}

运行结果是:

String                    StringBuffer           StringBuilder
8187毫秒                        0毫秒                        0毫秒
7906毫秒                        0毫秒                        16毫秒
7859毫秒                        0毫秒                        16毫秒
7921毫秒                        0毫秒                        0毫秒
7813毫秒                        16毫秒                       0毫秒
7890毫秒                        0毫秒                        0毫秒
7985毫秒                        15毫秒                       0毫秒
8438毫秒                        0毫秒                        0毫秒
8172毫秒                        0毫秒                        0毫秒
7937毫秒                        0毫秒                        16毫秒

上面字符串的拼接次数是30000,String的执行时间大概是8秒,由于StringBuffer和StringBuilder的执行速度比String要快很多,所以上面这两个字符串的执行时间几乎为零。

下面增大拼接次数到3000000,直接对比StringBuffer和StringBuilder的执行时间。

public class StringTest {
	public static void main(String[] args) {
		String value = "1234567890";
		int count = 3000000;		
		System.out.println("StringBuffer     StringBuilder");
		for (int j = 1; j <= 10; j++) {
			StringBuffer stringBuffer = new StringBuffer();
			StringBuilder stringBuilder = new StringBuilder();
			long begin = System.currentTimeMillis();
			
			for (int i = 0; i < count; i++) {
				stringBuffer.append(value);
			}
			
			long end1 = System.currentTimeMillis();
			System.out.print((end1 - begin) + "毫秒                        ");
			
			for (int i = 0; i < count; i++) {
				stringBuilder.append(value);
			}
			long end2 = System.currentTimeMillis();
			System.out.println((end2 - end1) + "毫秒");
		}
	}
}

程序的运行结果是

StringBuffer            StringBuilder
281毫秒                        219毫秒
234毫秒                        188毫秒
234毫秒                        219毫秒
219毫秒                        187毫秒
234毫秒                        204毫秒
250毫秒                        156毫秒
281毫秒                        234毫秒
266毫秒                        234毫秒
219毫秒                        188毫秒
234毫秒                        203毫秒

说明StringBuilder的执行效率比StringBuffer高一些,主要原因是StringBuffer要考虑线程安全。

public final class StringBuffer{
 	public synchronized StringBuffer append(String str) {
		super.append(str);
        		return this;
   	 }
}

 而StringBuilder则不需要考虑线程安全。

public final class StringBuilder{
	public StringBuilder append(String str) {
 		super.append(str);
       	 	return this;
    	}
}

 5、StringBuffer、StringBuilder指定初始容量

StringBuffer和StringBuilder的初始容量都是16,看以下源代码

public final class StringBuffer extends AbstractStringBuilder{
    public StringBuffer() {
	super(16);
    }
}

 

abstract class AbstractStringBuilder{
    AbstractStringBuilder(int capacity) {
        	value = new char[capacity];
    }
}

在字符串拼音的过程中,如果拼接后的长度超过原来的容量,StringBuffer会自动将容量扩展到原来的2倍左右,看以下源代码

public final class StringBuffer  extends AbstractStringBuilder{
    public synchronized StringBuffer append(String str) {
	super.append(str);
         return this;
    }
}

 

abstract class AbstractStringBuilder{
   public AbstractStringBuilder append(String str) {
	if (str == null) str = "null";
         int len = str.length();
	if (len == 0) return this;
	int newCount = count + len;
	if (newCount > value.length)
	    expandCapacity(newCount);
	str.getChars(0, len, value, count);
	count = newCount;
	return this;
    }

   void expandCapacity(int minimumCapacity) {
	int newCapacity = (value.length + 1) * 2;
         if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
         } else if (minimumCapacity > newCapacity) {
	   newCapacity = minimumCapacity;
	}
         value = Arrays.copyOf(value, newCapacity);
    }
}

因此,如果事先知道字符串拼接后的容量,事先就指定StringBuffer或StringBuilder的容量,那么执行速度就会快很多。

下面用程序比对一下两者的执行情况。

public static void specifyStringBufferCapacity(){
	String value = "1234567890";
	int count = 3000000;
		
	System.out.println("StringBuffer     StringBuffer(specify Capacity)");
	for (int j = 1; j <= 10; j++) {
		StringBuffer stringBuffer1 = new StringBuffer();
		StringBuffer stringBuffer2 = new StringBuffer(count*value.length());
		long begin = System.currentTimeMillis();
			
		for (int i = 0; i < count; i++) {
			stringBuffer1.append(value);
		}			
		long end1 = System.currentTimeMillis();
		System.out.print((end1 - begin) + "毫秒                               ");
			
		for (int i = 0; i < count; i++) {
			stringBuffer2.append(value);
		}
		long end2 = System.currentTimeMillis();
		System.out.println((end2 - end1) + "毫秒");
	}
}

执行结果如下:

StringBuffer          StringBuffer(specify Capacity)
313毫秒                               141毫秒
219毫秒                               125毫秒
218毫秒                               125毫秒
219毫秒                               125毫秒
219毫秒                               141毫秒
203毫秒                               141毫秒
219毫秒                               125毫秒
219毫秒                               125毫秒
234毫秒                               141毫秒
219毫秒                               140毫秒

从执行结果中可以看出,指定初始容量的执行时间比没指定初始容量的执行时间要快80%以上。

5、总结

三者的使用场景如下:

(1)String :字符串不需要经常改变

(2)StringBuffer:字符串经常需要改变且有线程安全问题

(3)StringBuilder:字符串经常需要改变且不考虑线程安全问题


 

 

 


 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值