【224期】Java 字符串拼接五种方法的性能比较分析,从执行100次到90万次?
点击上方“Java精选”,选择“设为星标”
别问别人为什么,多问自己凭什么!
下方有惊喜,留言必回,有问必答!
每天 08:15 更新文章,每天进步一点点...
字符串拼接一般使用“+”,但是“+”不能满足大批量数据的处理,Java中有以下五种方法处理字符串拼接,各有优缺点,程序开发应选择合适的方法实现。
加号 “+”
String contact() 方法
StringUtils.join() 方法
StringBuffer append() 方法
StringBuilder append() 方法
经过简单的程序测试,从执行100次到90万次的时间开销如下表:
由此可以看出:
方法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/ebooks
源代码,供参考
package cnblogs.twzheng.lab2;/*** @author Tan Wenzheng**/
import java.util.ArrayList;
import java.util.List;import org.apache.commons.lang3.StringUtils;public class TestString {private static final int max = 100;public void testPlus() {System.out.println(">>> testPlus() <<<");String str = "";long start = System.currentTimeMillis();for (int i = 0; i < max; i++) {str = str + "a";}long end = System.currentTimeMillis();long cost = end - start;System.out.println(" {str + \"a\"} cost=" + cost + " ms");}public void testConcat() {System.out.println(">>> testConcat() <<<");String str = "";long start = System.currentTimeMillis();for (int i = 0; i < max; i++) {str = str.concat("a");}long end = System.currentTimeMillis();long cost = end - start;System.out.println(" {str.concat(\"a\")} cost=" + cost + " ms");}public void testJoin() {System.out.println(">>> testJoin() <<<");long start = System.currentTimeMillis();List<String> list = new ArrayList<String>();for (int i = 0; i < max; i++) {list.add("a");}long end1 = System.currentTimeMillis();long cost1 = end1 - start;StringUtils.join(list, "");long end = System.currentTimeMillis();long cost = end - end1;System.out.println(" {list.add(\"a\")} cost1=" + cost1 + " ms");System.out.println(" {StringUtils.join(list, \"\")} cost=" + cost+ " ms");}public void testStringBuffer() {System.out.println(">>> testStringBuffer() <<<");long start = System.currentTimeMillis();StringBuffer strBuffer = new StringBuffer();for (int i = 0; i < max; i++) {strBuffer.append("a");}strBuffer.toString();long end = System.currentTimeMillis();long cost = end - start;System.out.println(" {strBuffer.append(\"a\")} cost=" + cost + " ms");}public void testStringBuilder() {System.out.println(">>> testStringBuilder() <<<");long start = System.currentTimeMillis();StringBuilder strBuilder = new StringBuilder();for (int i = 0; i < max; i++) {strBuilder.append("a");}strBuilder.toString();long end = System.currentTimeMillis();long cost = end - start;System.out.println(" {strBuilder.append(\"a\")} cost=" + cost + " ms");}
}
测试结果:
执行100次, private static final int max = 100;
>>> testPlus() <<<{str + "a"} cost=0 ms
>>> testConcat() <<<{str.concat("a")} cost=0 ms
>>> testJoin() <<<{list.add("a")} cost1=0 ms{StringUtils.join(list, "")} cost=20 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=0 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=0 ms
执行1000次, private static final int max = 1000;
>>> testPlus() <<<{str + "a"} cost=10 ms
>>> testConcat() <<<{str.concat("a")} cost=0 ms
>>> testJoin() <<<{list.add("a")} cost1=0 ms{StringUtils.join(list, "")} cost=20 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=0 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=0 ms
执行1万次, private static final int max = 10000;
>>> testPlus() <<<{str + "a"} cost=150 ms
>>> testConcat() <<<{str.concat("a")} cost=70 ms
>>> testJoin() <<<{list.add("a")} cost1=0 ms{StringUtils.join(list, "")} cost=30 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=0 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=0 ms
执行10万次, private static final int max = 100000;
>>> testPlus() <<<{str + "a"} cost=4198 ms
>>> testConcat() <<<{str.concat("a")} cost=1862 ms
>>> testJoin() <<<{list.add("a")} cost1=21 ms{StringUtils.join(list, "")} cost=49 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=10 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=10 ms
执行20万次, private static final int max = 200000;
>>> testPlus() <<<{str + "a"} cost=17196 ms
>>> testConcat() <<<{str.concat("a")} cost=7653 ms
>>> testJoin() <<<{list.add("a")} cost1=20 ms{StringUtils.join(list, "")} cost=51 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=20 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=16 ms
执行50万次, private static final int max = 500000;
>>> testPlus() <<<{str + "a"} cost=124693 ms
>>> testConcat() <<<{str.concat("a")} cost=49439 ms
>>> testJoin() <<<{list.add("a")} cost1=21 ms{StringUtils.join(list, "")} cost=50 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=20 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=10 ms
执行90万次, private static final int max = 900000;
>>> testPlus() <<<{str + "a"} cost=456739 ms
>>> testConcat() <<<{str.concat("a")} cost=186252 ms
>>> testJoin() <<<{list.add("a")} cost1=20 ms{StringUtils.join(list, "")} cost=68 ms
>>> testStringBuffer() <<<{strBuffer.append("a")} cost=30 ms
>>> testStringBuilder() <<<{strBuilder.append("a")} cost=24 ms
查看源代码,以及简单分析
String contact
和 StringBuffer
,StringBuilder
的源代码都可以在Java库里找到,有空可以研究研究。
推荐下自己做的 Spring boot 的实战项目:
https://gitee.com/yoodb/jing-xuan
1.其实每次调用contact()方法就是一次数组的拷贝,虽然在内存中是处理都是原子性操作,速度非常快,但是,最后的return语句会创建一个新String对象,限制了concat方法的速度。
public String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}int len = value.length;char buf[] = Arrays.copyOf(value, len + otherLen);str.getChars(buf, len);return new String(buf, true);}
2.StringBuffer 和 StringBuilder 的append方法都继承自AbstractStringBuilder,整个逻辑都只做字符数组的加长,拷贝,到最后也不会创建新的String对象,所以速度很快,完成拼接处理后在程序中用strBuffer.toString()
来得到最终的字符串。
/*** Appends the specified string to this character sequence.* <p>* The characters of the {@code String} argument are appended, in* order, increasing the length of this sequence by the length of the* argument. If {@code str} is {@code null}, then the four* characters {@code "null"} are appended.* <p>* Let <i>n</i> be the length of this character sequence just prior to* execution of the {@code append} method. Then the character at* index <i>k</i> in the new character sequence is equal to the character* at index <i>k</i> in the old character sequence, if <i>k</i> is less* than <i>n</i>; otherwise, it is equal to the character at index* <i>k-n</i> in the argument {@code str}.** @param str a string.* @return a reference to this object.*/public AbstractStringBuilder append(String str) {if (str == null) str = "null";int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}
/*** This method has the same contract as ensureCapacity, but is* never synchronized.*/private void ensureCapacityInternal(int minimumCapacity) {// overflow-conscious codeif (minimumCapacity - value.length > 0)expandCapacity(minimumCapacity);}/*** This implements the expansion semantics of ensureCapacity with no* size check or synchronization.*/void expandCapacity(int minimumCapacity) {int newCapacity = value.length * 2 + 2;if (newCapacity - minimumCapacity < 0)newCapacity = minimumCapacity;if (newCapacity < 0) {if (minimumCapacity < 0) // overflowthrow new OutOfMemoryError();newCapacity = Integer.MAX_VALUE;}value = Arrays.copyOf(value, newCapacity);}
3.字符串的加号“+” 方法, 虽然编译器对其做了优化,使用StringBuilder的append方法进行追加,但是每循环一次都会创建一个StringBuilder对象,且都会调用toString方法转换成字符串,所以开销很大。
注:执行一次字符串“+”,相当于
str = new StringBuilder(str).append("a").toString();
4.本文开头的地方统计了时间开销,根据上述分析再想想空间的开销。常说拿空间换时间,反过来是不是拿时间换到了空间呢,但是在这里,其实时间是消耗在了重复的不必要的工作上(生成新的对象,toString方法),所以对大批量数据做处理时,加号“+” 和 contact 方法绝对不能用,时间和空间成本都很高。
作者:老坛酸菜WH
https://www.cnblogs.com/twzheng/p/5923642.html
公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!
------ THE END ------
精品资料,超赞福利!
>Java精选面试题<
3000+ 道面试题在线刷,最新、最全 Java 面试题!
期往精选 点击标题可跳转
【216期】面试官问:Spring Boot 全局异常拦截器?
【217期】大文件上传:秒传、断点续传、分片上传
【218期】玩转 Java 注解:元注解、内置注解、自定义注解的原理和实现
【219期】为什么代码规范要求 SQL 语句不要过多的 join?
【220期】面试官:一致性 Hash 是什么?在负载均衡中的应用
【221期】扔掉工具类,Mybatis 一个简单配置搞定数据加密解密!
【222期】一个适用于 Spring Boot 项目的轻量级 HTTP 客户端框架
【223期】面试官问:什么是 YAML?和 Spring Boot 有什么关系?
技术交流群!
最近有很多人问,有没有读者&异性交流群,你懂的!想知道如何加入。加入方式很简单,有兴趣的同学,只需要点击下方卡片,回复“加群”,即可免费加入交流群!
文章有帮助的话,在看,转发吧!
【224期】Java 字符串拼接五种方法的性能比较分析,从执行100次到90万次?相关推荐
- Java遍历Map五种方法
一.Map集合遍历日常开发最常使用,简单总结五种方法差异. ①.Iterator+entrySet写法[推荐JDK8以下],Map.Entry是Map接口的内部接口,获取迭代器,然后依次取出每个迭代器 ...
- java 字符串 移位_使用位运算、值交换等方式反转java字符串-共四种方法
在本文中,我们将向您展示几种在Java中将String类型的字符串字母倒序的几种方法. StringBuilder(str).reverse() char[]循环与值交换 byte循环与值交换 apa ...
- delphi64位 char数组转换string中文乱码_使用位运算、值交换等方式反转java字符串-共四种方法...
在本文中,我们将向您展示几种在Java中将String类型的字符串字母倒序的几种方法. StringBuilder(str).reverse() char[]循环与值交换 byte循环与值交换 apa ...
- {转}Java 字符串分割三种方法
http://www.chenwg.com/java/java-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%88%86%E5%89%B2%E4%B8%89%E7%A7%8D%E6%9 ...
- java 字符串拆分技巧_{转}Java 字符串分割三种方法
http://www.chenwg.com/java/java-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%88%86%E5%89%B2%E4%B8%89%E7%A7%8D%E6%9 ...
- Java 字符串分割三种方法
最近在项目中遇到一个小问题,一个字符串分割成一个数组,类似String str="aaa,bbb,ccc"; 然后以","为分割符,将其分割成一个数组,用什么方 ...
- 用python画四叶草代码-python—字符串拼接三种方法
1.使用加号(+)号进行拼接 字符串拼接直接进行相加就可以,比较容易理解,但是一定要记得,变量直接相加,不是变量就要用引号引起来,不然会出错,另外数字是要转换为字符串才能够进行相加的,这点一定要记住, ...
- python字符串拼接变量_python—字符串拼接三种方法
1.使用加号(+)号进行拼接 字符串拼接直接进行相加就可以,比较容易理解,但是一定要记得,变量直接相加,不是变量就要用引号引起来,不然会出错,另外数字是要转换为字符串才能够进行相加的,这点一定要记住, ...
- Swift忽略大小写搜索子字符串的三种方法及性能对比
功能需求 在Swift中,字符串比较和搜索是很常见的操作.有时我们需要以特殊条件在一个字符串中搜索子字符串:比如忽略大小写或忽略变音符号. 在本篇博文里,我们将探讨Swift里三种特殊搜索字符串的方法 ...
最新文章
- sqlserver安装和简单的使用
- 分布式服务化系统一致性的“最佳实干”--转
- 资深美术师:3A转手游研发需要注意的方法
- [css] 举例说明:not()的使用场景有哪些
- java-linux-eclipse配置
- HIT Software Construction Review Notes(0-1 Introduction to the Course)
- zabbix安装笔记
- SQL转换时间的时分
- 常见NoSQL数据库概述
- Java利用MessageDigest获取字符串或文件MD5详解
- 网站头像: favicon.ico
- 系统管理指南:基本管理 第11 章• x86: 基于GRUB 的引导(任务)
- CDRX4X5X6X7X8下载安装失败的原因教程分享(CorelDRAW)
- 如何用excel做正交分析_利用Excel进行正交设计及分析
- python的OOP机制
- rockchip eDP 配置
- Excel分列-字母与汉字(前后)
- 字体加粗造成文字抖动
- 在excel中如何筛选重复数据_Excel数据筛选操作总结之数据透视表
- 最好用的数据库监控工具和数据库知识
热门文章
- SEO查询工具你只知道5118吗?这个工具包值得收藏
- chrony 时间同步详解
- 本题要求编写函数,将输入字符串的前3个字符移到最后
- ​真正的高手,都懂“概率权”
- windows 不小心删除了FlexNet Licensing Service 64 恢复方法
- C语言实现二叉树的非递归遍历
- SpringBoot 日志脱敏,开源组件太强了!
- 三态门有一个信号控制端en_单片机基础电路
- 宣化上人: “肉字里边两个人, 里边罩着外边人; 众生还吃众生肉, 仔细思量人吃人。”
- Google earth重登地图神器巅峰?看国产软件实力吊打行业老大