拼接字符串,用 “+” 还是StringBuilder.append()

倡议

在《阿里java开发手册》中,对于Java字符串的拼接有一条规则如下:

  • 22.【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。

“+”语法糖操作的本质

语法糖:语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。

“+”号操作符必须是字符串拼接最常用的一种了,没有之一。使用“+”拼接字符串,其实只是Java提供的一个语法糖。那么,我们就来解一解这个语法糖,看看他的内部原理到底是如何实现的。

还是这样一段代码。我们把他生成的字节码进行反编译,看看结果。

String str1= "唐伯虎";
 
String str2= "点香烟";
 
String endStr = str1+ "," + str2;

Dos反编译后的内容如下(反编译class文件的命令:javap -c 类名)。

String str1= "\u5510\u4f2f\u864e"; //唐伯虎
 
String str2= "\u70b9\u9999\u70df"; //点香烟
 
String endStr = (new StringBuilder()).append(str1).append(",").append(str2).toString();

通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使用其append方法进行处理的。

那么也就是说,Java中的“+”对字符串的拼接,其实现原理是使用StringBuilder.append()方法。

String、StringBuilder、StringBuffer性能比较

三者在执行速度方面的比较:StringBuilder > StringBuffer > String 。原因:

  • String:字符串常量
  • StringBuffer:字符串变量(有同步锁)
  • StringBuilder:字符串变量(无同步锁)

具体分析下String:从上面的名字可以看到,String是"字符串常量",也就是不可改变的对象。源码如下:

public final class String{}

对于上面这句话的理解你可能会产生这样一个疑问 ,比如这段代码:

String str = "唐伯虎";
 
str = str + "点香烟";
 
System.out.print(str); // result : "唐伯虎点香烟"

我们明明改变了String型的变量str啊,为什么说是没有改变呢?我们来看一下这张对String操作时内存变化的图:
在这里插入图片描述

我们可以看到,初始String值为"唐伯虎",然后在这个字符串后面加上新的字符串"点香烟",这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了"唐伯虎点香烟"字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。

而,对于StringBuilder、StringBuffer,他们俩均属于字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,速度自然就相对快了。
至于StringBuilder非线程安全、StringBuffer线程安全,这一点大家应该都清楚,StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。

一个特殊的例子

String str = "This is only a" + " simple" + " test";
 
StringBuffer builder = new StringBuilder("This is only a").append(" simple").append(" test");

这段代码,经测试发现,生成str对象的速度远高于builder,而这个时候StringBuilder居然速度上根本一点都不占优势。为什么呢?

其实这是JVM的一个把戏,实际上:

String str = “This is” + " a " + “demo”; 等同于 String str = “This is a demo”;

这是因为,在JVM优化时,如果是多个固定字符串拼接,会将这些固定字符串进行预处理,当成一个整体的字符串,相当于仅声明一个常量,所以并不需要太多的时间。

但大家这里要注意的是,如果字符串拼接的多个元素中有其他String对象的话,速度就没那么快了,譬如:

String str = "唐伯虎";
 
str = str + "点香烟";

或者:

String str5 = "啦啦啦";
 
String str6 = str5 + "嘻嘻嘻";

这时候JVM会规规矩矩的按照原来的方式去做。

总结

  1. 如果不是在循环体中进行字符串拼接的话,直接使用 String 的 “+” 就好了。

  2. 单线程循环中操作大量字符串数据 → StringBuilder.append()

  3. 多线程循环中操作大量字符串数据 → StringBuffer.append()

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悬浮海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值