前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java8 的 String Concatenate 比 StringBuilder Apporaches 慢?

Java8 的 String Concatenate 比 StringBuilder Apporaches 慢?

作者头像
shengjk1
发布2020-02-25 15:20:30
3520
发布2020-02-25 15:20:30
举报
文章被收录于专栏:码字搬砖码字搬砖

问题1: 文章说,大量 String + 连接比 通过 相应的StringBuilder 连接慢,要是在 Java7 之前我信,可以在 Java8 以及之后,编译器自动帮助我们把 + 优化成 StringBuilder (StringBuffer) 了。难道 Java8 的 String Concatenate 比 StringBuilder (StringBuffer) 慢?带着这样的疑问,决定好好的亲自试验一番。

/**
 * @author shengjk1
 * @date 2020/1/4
 */
public class Test {
	public static void main(String[] args) {
		int loopMax = 100000;
		
		long start = System.currentTimeMillis();
		String res = "";
		for (int i = 0; i < loopMax; i++) {
			res += i;
		}
		long end = System.currentTimeMillis();
		System.out.println((end - start));
		System.out.println("res" + res);
		
		StringBuilder builder = new StringBuilder();
		start = System.currentTimeMillis();
		res = "";
		builder.append(res);
		for (int i = 0; i < loopMax; i++) {
			builder.append(i);
		}
		end = System.currentTimeMillis();
		System.out.println((end - start));
		System.out.println("bulider" + builder.toString());
	}
}

res: 39733 ms bulider: 5 ms 注意是大量字符串的连接,特别是成为 热代码 之后,少量的字符串连接的差距就更显现不出来了。

问题来了,明明在 Java8 中 编译器将 String Concatenate 优化成了 StringBuilder ,为何差距还是这么明显?我们分别单独编译 String Concatenate 和 StringBuilder,然后分别单独看一下它们对应的机器指令是什么。

String Concatenate

       long start = System.currentTimeMillis();
		String res = "";
		for (int i = 0; i < loopMax; i++) {
			res += i;
		}
		long end = System.currentTimeMillis();
		System.out.println((end - start));
		System.out.println("res" + res);
 Code:
       0: ldc           #2                  // int 100000
       2: istore_1
       3: invokestatic  #3                  // Method java/lang/System.currentTimeMillis:()J
       6: lstore_2
       7: ldc           #4                  // String
       9: astore        4
      11: iconst_0
      12: istore        5
      #for 循环开始
      14: iload         5
      16: iload_1
      17: if_icmpge     48
      20: new           #5                  // class java/lang/StringBuilder
      23: dup
      24: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      27: aload         4
      29: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      32: iload         5
      34: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      37: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      40: astore        4
      42: iinc          5, 1
      45: goto          14
      # for 循环结束
      # 在 for 循环结束和开始当中,每遍历一次都会创建一个 StringBuilder 对象,与下面的代码相比这就是速度慢的地方
      48: invokestatic  #3                  // Method java/lang/System.currentTimeMillis:()J
      51: lstore        5
      53: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      56: lload         5
      58: lload_2
      59: lsub
      60: invokevirtual #11                 // Method java/io/PrintStream.println:(J)V
      63: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      66: new           #5                  // class java/lang/StringBuilder
      69: dup
      70: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      73: ldc           #12                 // String res
      75: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      78: aload         4
      80: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      83: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      86: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      89: return

StringBuilder

       StringBuilder builder = new StringBuilder();
		long start = System.currentTimeMillis();
		String res = "";
		builder.append(res);
		for (int i = 0; i < loopMax; i++) {
			builder.append(i);
		}
		long end = System.currentTimeMillis();
		System.out.println((end - start));
		System.out.println("bulider" + builder.toString());
 Code:
       0: ldc           #2                  // int 100000
       2: istore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: astore_2
      11: invokestatic  #5                  // Method java/lang/System.currentTimeMillis:()J
      14: lstore_3
      15: ldc           #6                  // String
      17: astore        5
      19: aload_2
      20: aload         5
      22: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: pop
      26: iconst_0
      27: istore        6
       # for 循环开始
      29: iload         6
      31: iload_1
      32: if_icmpge     48
      35: aload_2
      36: iload         6
      38: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      41: pop
      42: iinc          6, 1
      45: goto          29
      # for 循环结束
      48: invokestatic  #5                  // Method java/lang/System.currentTimeMillis:()J
      51: lstore        6
      53: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      56: lload         6
      58: lload_3
      59: lsub
      60: invokevirtual #10                 // Method java/io/PrintStream.println:(J)V
      63: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      66: new           #3                  // class java/lang/StringBuilder
      69: dup
      70: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      73: ldc           #11                 // String bulider
      75: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      78: aload_2
      79: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      82: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      85: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      88: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      91: return

最关键的部分其实是 for 循环部分,仔细看一下就会发现,对于 String Concatenate 每循环一次都会创建一个 StringBuilder,并且会 append两次然后 toString,并把结果赋值给 res,StringBuilder每次的创建和初始化也会浪费大量的时间以及内存。而 StringBuilder 仅仅创建一次,append 一次,toString 一次。

这也就解释了明明编译器自动帮助我们把 + 优化成 StringBuilder 了却还是 比 StringBuilder 慢的原因。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档