最近在头条上看到一篇帖子,说Java8开始,字符串拼接时,“+”会被编译成StringBuilder,所以,字符串的连接操作不用再考虑效率问题了,事实真的是这样吗?要搞明白,还是要看看Java编译后的字节码。

先比较这样两段代码。最简单的字符串拼接,一个用“+”,一个用StringBuilder。

public void useOperator(){ String a = "abc"; String b = "efg"; String c = a + b; System.out.println(c); } public void useStringBuilder(){ String a = "abc"; String b = "efg"; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(a); stringBuilder.append(b); System.out.println(stringBuilder.toString()); }

用javap去看这个代码的字节码,如下:

public void useOperator(); Code: '''a和b分别被存储到局部变量1和2中''' 0: ldc #2 // String abc 2: astore_1 3: ldc #3 // String efg 5: astore_2 '''"+"被转为StringBuilder''' 6: new #4 // class java/lang/StringBuilder '''复制一个引用,入栈''' 9: dup '''初始化StringBuilder,出栈''' 10: invokespecial #5 // Method java/lang/StringBuilder."":()V '''取出变量a''' 13: aload_1 '''调用append''' 14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; '''取出变量b''' 17: aload_2 '''调用append''' 18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; '''将toString返回的结果保存到局部变量3中,就是变量c''' 24: astore_3 25: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; '''取出变量c''' 28: aload_3 '''打印结果''' 29: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 32: return

对比源代码,useOperator中的c=a+b,被编译成了使用StringBuilder来操作,并依次把a和b添加到其中,看来确实jvm优化了“+”的拼接功能。

再看看useStringBuilder的字节码:

public void useStringBuilder(); Code: 0: ldc #2 // String abc 2: astore_1 3: ldc #3 // String efg 5: astore_2 6: new #4 // class java/lang/StringBuilder 9: dup 10: invokespecial #5 // Method java/lang/StringBuilder."":()V 13: astore_3 14: aload_3 15: aload_1 16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; '''append方法是带返回值的,使用invokevirtual指令,如果后面不继续使用返回结果,就需要将其pop出栈,否则后面的使用就乱了''' 19: pop 20: aload_3 21: aload_2 22: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 25: pop 26: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 29: aload_3 30: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 33: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 36: return

基本上和使用“+”的字节码是一致的,只不过是多了几次aload及pop,核心是一样的。

从上面的比较看,对于单一的字符串拼接,“+”确实等效于StringBuilder。能不能确认“+”是否可以替代StringBuilder,这些还不够,再看看稍微复杂一些的。

三个变量拼接。

public void useOperator(){ String a = "abc"; String b = "efg"; String c = "123"; String e = a + b + c; System.out.println(e); }

public void useOperator(); Code: 0: ldc #2 // String abc 2: astore_1 3: ldc #3 // String efg 5: astore_2 6: ldc #4 // String 123 8: astore_3 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."":()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 33: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 36: aload 4 38: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 41: return

貌似也没什么问题,依旧是对同一个StringBuilder对象操作。

再改一点,两次使用“+”操作符。看看会有什么不同吗?

public void useOperator(){ String a = "abc"; String b = "efg"; String c = "123"; String e = a + b; e = e + c; System.out.println(e); }

public void useOperator(); Code: 0: ldc #2 // String abc 2: astore_1 3: ldc #3 // String efg 5: astore_2 6: ldc #4 // String 123 8: astore_3 '''第一个StringBuilder''' 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."":()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: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 27: astore 4 '''第二个StringBuilder''' 29: new #5 // class java/lang/StringBuilder 32: dup 33: invokespecial #6 // Method java/lang/StringBuilder."":()V ...... 58: return

我们注意第9行和第29行,分别对应源码的下面两行。

String e = a + b;e = e + c;

这两句,竟然分别创建了一个StringBuilder,如果你再多写几个“+”操作,就会多创建几个StringBuilder,也即是说,每个“+”的出现,都会有一个StringBuilder被new出来,这个开销实在太大了。由此看来“+”还是不能完全替代StringBuilder,只能在极简情况下可以这样理解。

知道了这个结果,那我们就应该明白,假如你有一个for(或while)循环,里面有字符串的拼接操作,你应该使用“+”还是使用StringBuilder呢?

java8 stringbuilder_有了Java8的“+”真的可以不要StringBuilder了吗相关推荐

  1. Java8 Lamda和Stream流你真的会用了嘛?

    lambda表达式和stream流作为jdk8的新特性,极大程度的提高了java对函数式编程的便捷性,同时也提供了许多集合的流式操作,使我们在编程的过程中产生极大的便利,可以称之为颠覆性的更新. 目录 ...

  2. java8 stringbuilder_为什么 Java 8 中不再需要 StringBuilder 拼接字符串

    在Java开发者中,字符串的拼接占用资源高往往是热议的话题. 让我们深入讨论一下为什么会占用高资源. 在Java中,字符串对象是不可变的,意思是它一旦创建,你就无法再改变它.所以在我们拼接字符串的时候 ...

  3. java8 stringbuilder_为什么 Java 8 中不需要 StringBuilder 拼接字符串

    在Java开发者中,字符串的拼接占用资源高往往是热议的话题. 让我们深入讨论一下为什么会占用高资源. 在Java中,字符串对象是不可变的,意思是它一旦创建,你就无法再改变它.所以在我们拼接字符串的时候 ...

  4. 学妹惊呼:使用Java8改造后的模板方法模式真的是yyds

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 371 篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) 我们在日常开发中,经 ...

  5. 【爱上Java8】BigInteger在Java8中的改进

    BigInteger在Java8里增加了一组方法: 1 2 3 public byte byteValueExact() public int intValueExact() public long  ...

  6. java8与hibernate_Hibernate 使用java8 LocalDateTime 注意事项

    大家都知道,以前我们时间都用java.util.Date类型,但是现在都已经过时了, Java8里面新出来了一些API,LocalDate.LocalTime.LocalDateTime 非常好用 实 ...

  7. java8 optional使用_[Java8]如何正确使用Optional

    Optional是Java8提供的为了解决null安全问题的一个API.善用Optional可以使我们代码中很多繁琐.丑陋的设计变得十分优雅.这篇文章是建立在你对Optional的用法有一定了解的基础 ...

  8. java8 joda_Joda Time和Java8时差

    我正在寻找一个计算两个日期之间的月份的解决方案.我认为joda或java8时间可以做到.但是当我比较它们时,我发现了一些非常奇怪的东西. import java.text.ParseException ...

  9. java8双层for循环,Java8处理List的双层循环问题

    Java处理List的双层循环程序员经常遇到,一般都是当两个List某个值满足某条件时候,进行相应的处理: 1.list和map之间的相互转换 /** * 两个List对象当id相同的时候(注意是两个 ...

最新文章

  1. Netapp存储基础之WAFL, NVRAM, RAID, SnapShot
  2. when to book didi?
  3. SharpMap学习(2)
  4. restfull加签_SpringBoot RestFull API签名
  5. 数据结构折半查找算法C语言,数据结构C语言实现----折半查找
  6. 使用Nginx反向代理来实现简单的负载均衡
  7. incompatible jvm_JVM垃圾回收回收算法详解
  8. noip初赛试题 c语言,NOIP初赛试题提高组C语言.doc
  9. Codeforces Round #215 (Div. 2) B. Sereja and Suffixes map
  10. WinHex的使用指南(图文详细版)
  11. python cad按范围裁剪
  12. 艾永亮:不做读书人生意的书店,如此不正经却年赚超12亿?
  13. Linux编写脚本nsum求和,shell脚本学习与总结
  14. BIOS的两种引导模式
  15. 蓝瘦香菇!美国帅小伙作死尝试无人机剪头发
  16. ImageNet-1k分类数据集中英对照表 验证集类别解析
  17. Domain Adaption
  18. 阿里云增强版实人认证--银行卡要素核验
  19. 天问: 量子力学中的波函数到底表示什么?
  20. autoHotkey — 连击/双击/重复 按键触发

热门文章

  1. 有谁转行学java成功了的吗_毕业五六年转行学java可以吗,还能学会吗?
  2. mysql orderitems_【Mysql】教程全解(三)ORDER BY 排序
  3. thymeleaf学习
  4. 2020-09-09
  5. androidStudio使用卡顿
  6. 网易:层次遍历二叉树
  7. 时间 ,空间 ,物质
  8. 数据结构与算法 —— 链表linked list(05)
  9. # 20155337 《Android程序设计》实验四实验报告
  10. 网页中调用Google地图