Java字符串拼接用 “+” 还是 StringBuilder?

Java 中字符串拼接是一个常见操作,而选择合适的拼接方法对于性能有重要影响。

1. 使用 “+” 进行字符串拼接

首先看一个简单的字符串拼接示例:

java

String str1 = "he";
String str2 = "llo";
String str3 = "world";
String str4 = str1 + str2 + str3;

上述代码在 Java 编译后的字节码如下(见下图):

0:  ldc #2   // "he"
2:  astore_1
3:  ldc #3   // "llo"
5:  astore_2
6:  ldc #4   // "world"
8:  astore_3
9:  new #5   // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_3
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_4
32: return

通过上面的字节码可以看出,字符串对象通过“+”拼接的方式实际上是通过StringBuilder调用append()方法实现的。拼接完成后,通过toString()得到一个String对象。

2. 在循环内使用“+”进行字符串拼接的问题

在循环内使用“+”进行字符串拼接会有性能问题:

java

String[] arr = {"he", "llo", "world"};
String s = "";
for (int i = 0; i < arr.length; i++) {
    s += arr[i];
}
System.out.println(s);

对应的字节码如下(见下图):

0:  iconst_0
1:  istore_1
2:  iload_1
3:  aload_0
4:  arraylength
5:  if_icmpge 37
8:  new #6   // class java/lang/StringBuilder
11: dup
12: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
15: aload_2
16: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: aload_0
20: iload_1
21: aaload
22: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: astore_2
29: iinc 1, 1
32: goto 2
35: return

在循环中,StringBuilder对象是在每次循环时创建的,这会导致创建大量的临时StringBuilder对象,影响性能。

3. 使用 StringBuilder 进行字符串拼接

更好的做法是直接使用StringBuilder

java

String[] arr = {"he", "llo", "world"};
StringBuilder s = new StringBuilder();
for (String value : arr) {
    s.append(value);
}
System.out.println(s);

对应的字节码如下(见下图):

0:  new #6   // class java/lang/StringBuilder
3:  dup
4:  invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
7:  astore_1
8:  aload_0
9:  arraylength
10: istore_2
11: iconst_0
12: istore_3
13: iload_3
14: iload_2
15: if_icmpge 37
18: aload_1
19: aload_0
20: iload_3
21: aaload
22: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: iinc 3, 1
28: goto 13
31: return

可以看到,StringBuilder对象是在循环外创建的,并且在整个循环过程中复用同一个StringBuilder对象,从而避免了创建大量的临时对象。

4. JDK 9 的改进

JDK 9 中,字符串相加“+”的实现进行了优化,改用了动态方法makeConcatWithConstants()。这样在使用“+”进行字符串拼接时,不再产生大量的临时对象。

java

String s1 = "hello";
String s2 = "world";
String s3 = s1 + s2;

在 JDK 9 中对应的字节码如下:

0:  ldc #2   // "hello"
2:  astore_1
3:  ldc #3   // "world"
5:  astore_2
6:  aload_1
7:  aload_2
8:  invokedynamic #4,  0  // Bootstrap methods
13: astore_3
14: return

invokedynamic指令调用了makeConcatWithConstants方法,从而避免了创建多余的StringBuilder对象,提高了性能。

总结

  • 单次字符串拼接:使用“+”操作符,因为编译器会优化成StringBuilder操作。
  • 循环中的字符串拼接:建议使用StringBuilder,避免创建大量临时对象。
  • JDK 9 及以后:使用“+”进行字符串拼接已经优化,不会有性能问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值