java中字符串String拼接。
1 是不是字符串拼接中出现了 + 符号就效率低
答案:不是。在+前后连接的都是字面值的时候,在编译之后这个+不存在。
例子:String s = “A” + “B” + “C”; 编译后就是String s = “ABC”;如图:字面值指的是用双引号括起来的,比如:”A”、 “java” 等等。
图中代码编译后再反编译得到结果,如图:
从几个例子可见,+前后的换行和空字符串还有缩进等都没有任何影响,由连接字面值的+编译后不存在这个特性。可以很方便的声明需要有格式才有高可读性的内容,比如sql、xml等。
第一种方式和第二种方式,显然第二种可读性更好,并且性能没有任何影响。并且两种方式声明的不管用==还是equals还是hashCode还是compareTo还是identityHashCode比较,结果都是完全一致的,因为第二个只是把第一个从常量池里拿出来而已。记住是一个 String声明中的+连接的全是字面值的时候。
如果出现了下图这种代码,那真是弄巧成拙。明明一次声明就完事然后直接从常量池拿的问题,搞得每次都动态去拼接出来,关键是这么做没一点意义完全是没事找事,还暴露了自以为是。
2 当+前或后连接的不是字面值的时候。如:
String a = “A”; String s = a + “BC”;这时候+的出现是不是导致了效率低,然后可以用StringBuffer或者jdk5的StringBuilder。看实验结果。
结果是第16行和19行耗时相差无几,因为 16行的+不是前后都是字面值,编译后就是19的形式。用一个建造者模式的StringBuilder不停去append,最后toString。
那既然使用+最好的情况是无任何性能上的影响,最坏的情况是和使用StringBuilder一致,那还为什么使用StringBuilder呢还不是全都用+?看下面这种情况,string在循环外声明。
这时候20行编译成 new StringBuilder(string).append(a).append(“BC”).toString()的形式,每一次循环都会执行一次这个语句,每次循环都new 一个StringBuilder 然后append 最后toSting,
显然效率远远低于第二种方式只new 一个 StringBuilder ,然后在循环里只调用append。
还有就是上图的sql,因为sql 的and条件不确定,所以where 后面不确定会有多少个and xxx = xx的语句,这时候使用StringBuilder也是效率高于+=的。原因同上面while循环,因为每个+=都编译成new StringBuilder(string).append(a).append(“BC”).toString()的形式。
然后33行,是强烈不建议的方式。因为既然使用了StringBuilder,33行这个append里面的+又编译成一个 new StringBuilder(” and u.name = “).append(name).toString()的方式,实在是画蛇添足。这句builder.append(XX)括号里的这个XX又new了一个StringBuilder.。
结论:
1 java中字符串拼接不是出现了+就效率低,只有在+前或后至少一个不是字面值的时候才效率低,说效率低也不太准确,原因在上面,因为+会编译成append的形式,与使用Stringbuilder区别不大。准确来说应该是+=中+才会导致效率低,并且是在多次调用+=的情况下,因为 单独的+会编译成append 而+=会编译成 new StringBuillder(xx).append(xx).toString(),多次使用+=会生成多个new StringBuilder,此时效率才低于显示使用StringBuilder。
2 在简单的拼接中,使用+和显示使用StringBuilder基本没区别。比如京东的通知消息:
String msg = “您的订单号” + 订单号 + “已完成,感谢您对京东的支持”;和
String msg = new Stringbuilder(“您的订单号”).append(订单号).append(“已完成,感谢您对京东的支持”).toString();这两种方式基本没区别,因为前者会编译成后者的形式。
String msg = new Stringbuilder(“您的订单号”).append(订单号 + “已完成,感谢您对京东的支持”).toString();如果出现这种方式使用了Stringbuilder还用+并且+前后还不都是字面值,那就又是弄巧成拙的代码。
只有在使用+时出现多个=赋值操作时,才推荐显示使用StringBuilder,如上面拼sql的例子和循环里拼接字符串。否则推荐使用简单方便的+符号。
当然还有+连接或append中的内容如果是自定义类型,那这个类型需要覆盖掉toString,不然是Object的类名@哈希吗、不存在线程安全的情况下用StringBuilder而不是Buffer如上面的拼接sql的情况、StringBuilder/Buffer初始化时尽量指定容量等等问题….
最后图片6种形式,
耗时是 1和2最低并且相同,3、4 、5 、6差不多一致,4要稍慢,6更好一些,实际应用中很多情况下都是可以算出实际所需容量的,要好于默认的16然后 *2 + 2去扩容。