您的位置:首页 > 移动开发

String+String和StringBuilder.append(String)的效率和区别

2015-06-30 14:50 405 查看
在写程序的时候以前常用String来直接加,后面慢慢发现这样的效率比较低下,后来改成用StringBuilder或者StringBuffer来进行字符串的拼接。有同事告诉我,其实直接用String+String的方式[下称S+S方式],编译器自己会弄成StringBuilder.append()的方式[下称append方式],我也没有实验过,也不好反对,但是我感觉应该是不对的,所以就有了以下的实验。

实验很简单,就是初始化一个字符串“1”,然后在这个基础上循环一定次数的拼接字符串“1”。

一、首先看看两种方式的运行时间:

1、S+S方式

public class TestString {
public static void main(String[] args) {
String a="1";
long startTime=System.currentTimeMillis();
for(int i=0;i<100000;i++){
a=a+"1";
}
long endTime=System.currentTimeMillis();
System.out.print(endTime-startTime);
}
}
运行时间:



2、append方式

public class TestBuilding {
public static void main(String[] args) {
StringBuilder a=new StringBuilder("1");
long startTime=System.currentTimeMillis();
for(int i=0;i<1000000;i++){
a.append("1");
}
long endTime=System.currentTimeMillis();
System.out.print(endTime-startTime);
}
}
运行时间:



S+S方式消耗的时间为9099,append方式消耗的时间为17,很明显,S+S方式非常耗费时间,不知道各位看清楚没,S+S只循环了10W次,而append循环了100W次

二、看看两种方式的字节码

1、S+S方式

Compiled from "TestString.java"
public class TestString extends java.lang.Object{
public TestString();
Code:
0:	aload_0
1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
4:	return

public static void main(java.lang.String[]);
Code:
0:	ldc	#2; //String 1
2:	astore_1
3:	invokestatic	#3; //Method java/lang/System.currentTimeMillis:()J
6:	lstore_2
7:	iconst_0
8:	istore	4
10:	iload	4
12:	ldc	#4; //int 100000
14:	if_icmpge	43
17:	new	#5; //class java/lang/StringBuilder
20:	dup
21:	invokespecial	#6; //Method java/lang/StringBuilder."<init>":()V
24:	aload_1
25:	invokevirtual	#7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28:	ldc	#2; //String 1
30:	invokevirtual	#7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
33:	invokevirtual	#8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
36:	astore_1
37:	iinc	4, 1
40:	goto	10
43:	invokestatic	#3; //Method java/lang/System.currentTimeMillis:()J
46:	lstore	4
48:	getstatic	#9; //Field java/lang/System.out:Ljava/io/PrintStream;
51:	lload	4
53:	lload_2
54:	lsub
55:	invokevirtual	#10; //Method java/io/PrintStream.print:(J)V
58:	return

}


2、append方式

Compiled from "TestBuilding.java"
public class TestBuilding extends java.lang.Object{
public TestBuilding();
Code:
0:	aload_0
1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
4:	return

public static void main(java.lang.String[]);
Code:
0:	new	#2; //class java/lang/StringBuilder
3:	dup
4:	ldc	#3; //String 1
6:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
9:	astore_1
10:	invokestatic	#5; //Method java/lang/System.currentTimeMillis:()J
13:	lstore_2
14:	iconst_0
15:	istore	4
17:	iload	4
19:	ldc	#6; //int 1000000
21:	if_icmpge	37
24:	aload_1
25:	ldc	#3; //String 1
27:	invokevirtual	#7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30:	pop
31:	iinc	4, 1
34:	goto	17
37:	invokestatic	#5; //Method java/lang/System.currentTimeMillis:()J
40:	lstore	4
42:	getstatic	#8; //Field java/lang/System.out:Ljava/io/PrintStream;
45:	lload	4
47:	lload_2
48:	lsub
49:	invokevirtual	#9; //Method java/io/PrintStream.print:(J)V
52:	return

}
比较两个方式的字节码文件,发现都有StringBuilder的影子,但是不同的是S+S方式每次都有toString这个方法(见S+S字节码33行)并且编译器优化的StringBuilder是每次循环都会new一个,会产生更多的对象所以及其的慢

具体内存变化见图


所以,大量字符串拼接的时候,用StringBuild更理想,更效率,两个字符串拼接的时候倒是无所谓。另外StringBuilder和StringBuffer都比S+S方式更优化,只是StringBuilder是非线程安全的,而StringBuffer是线程安全的

另外附上S+S方式,循环100W次JVM的内存变化图(并未循环完100W次)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: