为何不要在for循环里用+=来拼接字符串?
一. 案例Demo
先看下这个代码:
import org.junit.Test;
public class TestString {
@Test
public void testString() {
String str="aaaaaaaaaaaaaaaaa";
for (int i = 0; i < 1000; i++) {
str+=str;
}
}
}
然后配置下相关的参数:
-verbose:ge -Xms2m -Xmx2m -Xmn1m -XX:+PrintGCDetails -XX:SurvivorRatio=8
运行后的结果如下,可见抛了OOM
为什么会造成这种情况?我们来分析下+=操作发生了什么。
二. 剖析+=操作的内部原理
找到这个类的class
文件,一般maven install
后,就会生成对应的target
目录,下面就有,如图:
在该class
文件所在目录中输入命令:
javap -c TestString.class > 1.txt
然后会生成对应的txt文件,打开查看里面的内容:
Compiled from "TestString.java"
public class TestString {
public TestString();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void testString();
Code:
0: ldc #2 // String aaaaaaaaaaaaaaaaa
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: sipush 1000
9: if_icmpge 37
12: new #3 // class java/lang/StringBuilder
15: dup
16: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
19: aload_1
20: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: aload_1
24: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_1
31: iinc 2, 1
34: goto 5
37: return
}
仔细观察code12~27
之间的内容,我们可以发现,原代码为:
str+=str;
经过反编译后,其步骤如下:
new StringBuilder()
StringBuilder.append()
StringBuilder.toString()
我们发现,字符串在做 +
拼接的时候,实际上会new
一个StringBuilder
对象,那么如果我们循环了10000
次,也就是会new
出10000个StringBuilder
对象。
如果把上述代码改成这样:(加上同样的VM配置)
@Test
public void testStringBuilder() {
String str ="aaaaaaaaaaaaaaaaa";
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 1000; i++) {
builder.append(str);
}
}
运行结果如下:能正常运行
因此,有个结论:在for循环里面进行字符串+=拼接的这种写法非常的占用内存。 并且alibaba开发手册中推荐在for
循环中,对于字符串的拼接,用StringBuilder.append()
来代替+=
。
文章到这里就结束啦,感谢各位读者~