专业编程基础技术教程

网站首页 > 基础教程 正文

Java字符串连接你用+还是用StringBuilder

ccvgpt 2024-09-08 12:45:11 基础教程 14 ℃

前言

据我所知字符串确实已经成为 Java 开发人员最常用的类了,而且是大量使用。我们都知道,String 其实是封装了字符,所以俩字符串连接就是将字符串对象里面的字符连起来。很多人习惯使用+来连接字符串,也有人会用 StringBuilder 的append方法。

Java字符串连接你用+还是用StringBuilder

"+"编译后

看看如果我们在程序中直接使用+来连接字符串的情况,用下面一个简单的例子来说明,进行两个字符串连接操作,即s3 = s1 + s2。

public class TestString {
 public static void main(String[] args) {
 String s1 = "www";
 String s2 = "ccc";
 String s3 = s1 + s2;
 }
}

接着javap -c TestString.class看一下编译后的情况,可以看到编译器其实是对+进行了转换的,转成了 StringBuilder 对象来操作了,首先使用 s1 创建 StringBuilder 对象,然后用 append方法连接 s2,最后调用toString方法完成。

public class com.seaboat.string.TestString {
 public com.seaboat.string.TestString();
 Code:
 0: aload_0
 1: invokespecial #8 // Method java/lang/Object."<init>":()V
 4: return
 public static void main(java.lang.String[]);
 Code:
 0: ldc #16 // String www
 2: astore_1
 3: ldc #18 // String ccc
 5: astore_2
 6: new #20 // class java/lang/StringBuilder
 9: dup
 10: aload_1
 11: invokestatic #22 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
 14: invokespecial #28 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
 17: aload_2
 18: invokevirtual #31 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 21: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
 24: astore_3
 25: return
}

"+"与"append"等价吗

前面可以看到+在编译器作用下都会转成 StringBuilder 的append方法执行,所以如果抛开运行效率来说,它们其实本质是一样的。

本质一样是否就能说明它们时等价的呢?或者说能否为了方便直接用+来连接字符串,剩下的事就交给编译器了?继续看个例子,在这个例子中有个 for 循环进行字符串连接操作。

public class TestString2 {
 public static void main(String[] args) {
 String s = "www";
 for (int i = 0; i < 10; i++)
 s += i;
 }
}

编译后的情况如下,不熟悉指令没关系,我们只看重要的部分,if_icmplt 8,这个就是 for 循环的条件判断,小于10则不断跳到8的位置,8后面其实就是创建 StringBuilder 对象,并以本地变量s的值初始化该对象,接着再将本地变量i append到 StringBuilder 对象中,最后调用toString方法将所得值存到本地变量s。

这样来看循环中每次都要创建 StringBuilder 对象,而且要调用toString方法,这样的执行效率显然比较低,而且增加了 GC 的压力。

public class com.seaboat.string.TestString2 {
 public com.seaboat.string.TestString2();
 Code:
 0: aload_0
 1: invokespecial #8 // Method java/lang/Object."<init>":()V
 4: return
 public static void main(java.lang.String[]);
 Code:
 0: ldc #16 // String www
 2: astore_1
 3: iconst_0
 4: istore_2
 5: goto 30
 8: new #18 // class java/lang/StringBuilder
 11: dup
 12: aload_1
 13: invokestatic #20 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
 16: invokespecial #26 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
 19: iload_2
 20: invokevirtual #29 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
 23: invokevirtual #33 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
 26: astore_1
 27: iinc 2, 1
 30: iload_2
 31: bipush 10
 33: if_icmplt 8
 36: return
}

友好写法

把事情都丢给编译器是不友好的,为了能让程序执行更加高效,最好是我们自己来控制 StringBuilder 的实例,比如下面,只创建一个 StringBuilder 实例,后面用append方法连接字符串。

public class TestString3 {
 public static void main(String[] args) {
 StringBuilder sb = new StringBuilder("www");
 for (int i = 0; i < 10; i++)
 sb.append(i);
 }
}

编译后的情况如下,首先创建一个 StringBuilder 对象,使用字符串"www"来实例化该对象,接着循环调用append方法将本地变量i添加到 StringBuilder 对象中。

public class com.seaboat.string.TestString3 {
 public com.seaboat.string.TestString3();
 Code:
 0: aload_0
 1: invokespecial #8 // Method java/lang/Object."<init>":()V
 4: return
 public static void main(java.lang.String[]);
 Code:
 0: new #16 // class java/lang/StringBuilder
 3: dup
 4: ldc #18 // String www
 6: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
 9: astore_1
 10: iconst_0
 11: istore_2
 12: goto 24
 15: aload_1
 16: iload_2
 17: invokevirtual #23 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
 20: pop
 21: iinc 2, 1
 24: iload_2
 25: bipush 10
 27: if_icmplt 15
 30: return
}

最近发表
标签列表