java字符串连接方式(五种方法的性能比较分析)

别问别人为什么,多问自己凭什么!

下方有惊喜,留言必回,有问必答!

每天08:15更新文章,每天进步一点点…

字符串拼接一般使用“ ”,但是“ ”不能满足大批量数据的处理,Java中有以下五种方法处理字符串拼接,各有优缺点,程序开发应选择合适的方法实现。

加号 “ ”String contact() 方法StringUtils.join() 方法StringBuffer append() 方法StringBuilder append() 方法

经过简单的程序测试,从执行100次到90万次的时间开销如下表:

java字符串连接方式(五种方法的性能比较分析)

由此可以看出:

方法1 加号 “ ” 拼接 和 方法2 String contact() 方法 适用于小数据量的操作,代码简洁方便,加号“ ” 更符合我们的编码和阅读习惯;

方法3 StringUtils.join() 方法 适用于将ArrayList转换成字符串,就算90万条数据也只需68ms,可以省掉循环读取ArrayList的代码;

方法4 StringBuffer append() 方法 和 方法5 StringBuilder append() 方法 其实他们的本质是一样的,都是继承自AbstractStringBuilder,效率最高,大批量的数据处理最好选择这两种方法。

方法1 加号 “ ” 拼接 和 方法2 String contact() 方法 的时间和空间成本都很高(分析在本文末尾),不能用来做批量数据的处理。

推荐下自己几个月熬夜整理的面试资料大全:

https://gitee.com/yoodb/eboo??ks

源代码,供参考

packagecnblogs.twzheng.lab2;/***@authorTanWenzheng**/importjava.util.ArrayList;importjava.util.List;importorg.apache.commons.lang3.StringUtils;publicclassTestString{privatestaticfinalintmax=100;publicvoidtestPlus(){System.out.println(“>>>testPlus()<<<“);Stringstr=””;longstart=System.currentTimeMillis();for(inti=0;i<max;i ){str=str “a”;}longend=System.currentTimeMillis();longcost=end-start;System.out.println(“{str \”a\”}cost=” cost “ms”);}publicvoidtestConcat(){System.out.println(“>>>testConcat()<<<“);Stringstr=””;longstart=System.currentTimeMillis();for(inti=0;i<max;i ){str=str.concat(“a”);}longend=System.currentTimeMillis();longcost=end-start;System.out.println(“{str.concat(\”a\”)}cost=” cost “ms”);}publicvoidtestJoin(){System.out.println(“>>>testJoin()<<<“);longstart=System.currentTimeMillis();List<String>list=newArrayList<String>();for(inti=0;i<max;i ){list.add(“a”);}longend1=System.currentTimeMillis();longcost1=end1-start;StringUtils.join(list,””);longend=System.currentTimeMillis();longcost=end-end1;System.out.println(“{list.add(\”a\”)}cost1=” cost1 “ms”);System.out.println(“{StringUtils.join(list,\”\”)}cost=” cost “ms”);}publicvoidtestStringBuffer(){System.out.println(“>>>testStringBuffer()<<<“);longstart=System.currentTimeMillis();StringBufferstrBuffer=newStringBuffer();for(inti=0;i<max;i ){strBuffer.append(“a”);}strBuffer.toString();longend=System.currentTimeMillis();longcost=end-start;System.out.println(“{strBuffer.append(\”a\”)}cost=” cost “ms”);}publicvoidtestStringBuilder(){System.out.println(“>>>testStringBuilder()<<<“);longstart=System.currentTimeMillis();StringBuilderstrBuilder=newStringBuilder();for(inti=0;i<max;i ){strBuilder.append(“a”);}strBuilder.toString();longend=System.currentTimeMillis();longcost=end-start;System.out.println(“{strBuilder.append(\”a\”)}cost=” cost “ms”);}}

测试结果:

执行100次, private static final int max = 100;>>>testPlus()<<<{str “a”}cost=0ms>>>testConcat()<<<{str.concat(“a”)}cost=0ms>>>testJoin()<<<{list.add(“a”)}cost1=0ms{StringUtils.join(list,””)}cost=20ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=0ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=0ms执行1000次, private static final int max = 1000;>>>testPlus()<<<{str “a”}cost=10ms>>>testConcat()<<<{str.concat(“a”)}cost=0ms>>>testJoin()<<<{list.add(“a”)}cost1=0ms{StringUtils.join(list,””)}cost=20ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=0ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=0ms执行1万次, private static final int max = 10000;>>>testPlus()<<<{str “a”}cost=150ms>>>testConcat()<<<{str.concat(“a”)}cost=70ms>>>testJoin()<<<{list.add(“a”)}cost1=0ms{StringUtils.join(list,””)}cost=30ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=0ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=0ms执行10万次, private static final int max = 100000;>>>testPlus()<<<{str “a”}cost=4198ms>>>testConcat()<<<{str.concat(“a”)}cost=1862ms>>>testJoin()<<<{list.add(“a”)}cost1=21ms{StringUtils.join(list,””)}cost=49ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=10ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=10ms执行20万次, private static final int max = 200000;>>>testPlus()<<<{str “a”}cost=17196ms>>>testConcat()<<<{str.concat(“a”)}cost=7653ms>>>testJoin()<<<{list.add(“a”)}cost1=20ms{StringUtils.join(list,””)}cost=51ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=20ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=16ms执行50万次, private static final int max = 500000;>>>testPlus()<<<{str “a”}cost=124693ms>>>testConcat()<<<{str.concat(“a”)}cost=49439ms>>>testJoin()<<<{list.add(“a”)}cost1=21ms{StringUtils.join(list,””)}cost=50ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=20ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=10ms执行90万次, private static final int max = 900000;>>>testPlus()<<<{str “a”}cost=456739ms>>>testConcat()<<<{str.concat(“a”)}cost=186252ms>>>testJoin()<<<{list.add(“a”)}cost1=20ms{StringUtils.join(list,””)}cost=68ms>>>testStringBuffer()<<<{strBuffer.append(“a”)}cost=30ms>>>testStringBuilder()<<<{strBuilder.append(“a”)}cost=24ms

查看源代码,以及简单分析

String contact和StringBuffer,StringBuilder的源代码都可以在Java库里找到,有空可以研究研究。

推荐下自己做的 Spring boot 的实战项目:

https://gitee.com/yoodb/jing-xuan

1.其实每次调用contact()方法就是一次数组的拷贝,虽然在内存中是处理都是原子性操作,速度非常快,但是,最后的return语句会创建一个新String对象,限制了concat方法的速度。

publicStringconcat(Stringstr){intotherLen=str.length();if(otherLen==0){returnthis;}intlen=value.length;charbuf[]=Arrays.copyOf(value,len otherLen);str.getChars(buf,len);returnnewString(buf,true);}

2.StringBuffer 和 StringBuilder 的append方法都继承自AbstractStringBuilder,整个逻辑都只做字符数组的加长,拷贝,到最后也不会创建新的String对象,所以速度很快,完成拼接处理后在程序中用strBuffer.toString()来得到最终的字符串。

/***Appendsthespecifiedstringtothischaractersequence.*<p>*Thecharactersofthe{@codeString}argumentareappended,in*order,increasingthelengthofthissequencebythelengthofthe*argument.If{@codestr}is{@codenull},thenthefour*characters{@code”null”}areappended.*<p>*Let<i>n</i>bethelengthofthischaractersequencejustpriorto*executionofthe{@codeappend}method.Thenthecharacterat*index<i>k</i>inthenewcharactersequenceisequaltothecharacter*atindex<i>k</i>intheoldcharactersequence,if<i>k</i>isless*than<i>n</i>;otherwise,itisequaltothecharacteratindex*<i>k-n</i>intheargument{@codestr}.**@paramstrastring.*@returnareferencetothisobject.*/publicAbstractStringBuilderappend(Stringstr){if(str==null)str=”null”;intlen=str.length();ensureCapacityInternal(count len);str.getChars(0,len,value,count);count =len;returnthis;}/***ThismethodhasthesamecontractasensureCapacity,butis*neversynchronized.*/privatevoidensureCapacityInternal(intminimumCapacity){//overflow-consciouscodeif(minimumCapacity-value.length>0)expandCapacity(minimumCapacity);}/***ThisimplementstheexpansionsemanticsofensureCapacitywithno*sizecheckorsynchronization.*/voidexpandCapacity(intminimumCapacity){intnewCapacity=value.length*2 2;if(newCapacity-minimumCapacity<0)newCapacity=minimumCapacity;if(newCapacity<0){if(minimumCapacity<0)//overflowthrownewOutOfMemoryError();newCapacity=Integer.MAX_VALUE;}value=Arrays.copyOf(value,newCapacity);}

3.字符串的加号“ ” 方法, 虽然编译器对其做了优化,使用StringBuilder的append方法进行追加,但是每循环一次都会创建一个StringBuilder对象,且都会调用toString方法转换成字符串,所以开销很大。

注:执行一次字符串“ ”,相当于str = new StringBuilder(str).append(“a”).toString();

4.本文开头的地方统计了时间开销,根据上述分析再想想空间的开销。常说拿空间换时间,反过来是不是拿时间换到了空间呢,但是在这里,其实时间是消耗在了重复的不必要的工作上(生成新的对象,toString方法),所以对大批量数据做处理时,加号“ ” 和 contact 方法绝对不能用,时间和空间成本都很高。

https://www.cnblogs.com/twzheng/p/5923642.html

精品资料,超赞福利!

>Java精选面试题<3000 道面试题在线刷,最新、最全 Java 面试题!

【216期】面试官问:Spring Boot 全局异常拦截器?

【217期】大文件上传:秒传、断点续传、分片上传

【218期】玩转 Java 注解:元注解、内置注解、自定义注解的原理和实现

【219期】为什么代码规范要求 SQL 语句不要过多的 join?

【220期】面试官:一致性 Hash 是什么?在负载均衡中的应用

【221期】扔掉工具类,Mybatis 一个简单配置搞定数据加密解密!

【222期】一个适用于 Spring Boot 项目的轻量级 HTTP 客户端框架

【223期】面试官问:什么是 YAML?和 Spring Boot 有什么关系?

技术交流群!

发表评论

登录后才能评论