点击上方 好好学java ,选择 星标 公众号

重磅资讯、干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多

作者|@后青春期的Keats

www.cnblogs.com/keatsCoder/p/13212289.html

 引言

都说 StringBuilder 在处理字符串拼接上效率要强于 String,但有时候我们的理解可能会存在一定的偏差。最近我在测试数据导入效率的时候就发现我以前对 StringBuilder 的部分理解是错误的。后来我通过实践测试 + 找原理 的方式搞清楚了这块的逻辑。现在将过程分享给大家

测试用例

我们的代码在循环中拼接字符串一般有两种情况

  • 第一种就是每次循环将对象中的几个字段拼接成一个新字段,再赋值给对象

  • 第二种操作是在循环外创建一个字符串对象,每次循环向该字符串拼接新的内容。循环结束后得到拼接好的字符串

对于这两种情况,我创建了两个对照组

第一组:

在每次 For 循环中拼接字符串,即拼即用、用完即毁。分别使用 String 和 StringBuilder 拼接

    /*** 循环内 String 拼接字符串,一次循环后销毁*/public static void useString(){for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {String str = str1 + i + str2 + i + str3 + i + str4 ;}}/*** 循环内 使用 StringBuilder 拼接字符串,一次循环后销毁*/public static void useStringBuilder(){for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {StringBuilder sb = new StringBuilder();String s = sb.append(str1).append(i).append(str2).append(i).append(str3).append(i).append(str4).toString();}}

第二组:

多次 For 循环拼接一个字符串,循环结束后使用字符串,使用后由垃圾回收器回收。也是分别使用 String 和 StringBuilder 拼接

    /*** 多次循环拼接成一个字符串 用 String*/public static void useStringSpliceOneStr (){String str = "";for (int i = 0; i < CYCLE_NUM_LOWER; i++) {str += str1 + str2 + str3 + str4 + i;}}/*** 多次循环拼接成一个字符串 用 StringBuilder*/public static void useStringBuilderSpliceOneStr(){StringBuilder sb = new StringBuilder();for (int i = 0; i < CYCLE_NUM_LOWER; i++) {sb.append(str1).append(str2).append(str3).append(str4).append(i);}}

为了保证测试质量,在每个测试项目进行前。线程休息 2s,之后空跑 5 次热身。最后执行 5 次求平均时间的方式计算时间

   
 public static int executeSometime(int kind, int num) throws InterruptedException {Thread.sleep(2000);int sum = 0;for (int i = 0; i < num + 5; i++) {long begin = System.currentTimeMillis();switch (kind){case 1:useString();break;case 2:useStringBuilder();break;case 3:useStringSpliceOneStr();break;case 4:useStringBuilderSpliceOneStr();break;default:return 0;}long end = System.currentTimeMillis();if(i > 5){sum += (end - begin);}}return sum / num;}

主方法

public class StringTest {public static final int CYCLE_NUM_BIGGER = 10_000_000;public static final int CYCLE_NUM_LOWER = 10_000;public static final String str1 = "张三";public static final String str2 = "李四";public static final String str3 = "王五";public static final String str4 = "赵六";public static void main(String[] args) throws InterruptedException {int time = 0;int num = 5;time = executeSometime(1, num);System.out.println("String拼接 "+ CYCLE_NUM_BIGGER +" 次," + num + "次平均时间:" + time + " ms");time = executeSometime(2, num);System.out.println("StringBuilder拼接 "+ CYCLE_NUM_BIGGER +" 次," + num + "次平均时间:" + time + " ms");time = executeSometime(3, num);System.out.println("String拼接单个字符串 "+ CYCLE_NUM_LOWER +" 次," + num + "次平均时间:" + time + " ms");time = executeSometime(4, num);System.out.println("StringBuilder拼接单个字符串 "+ CYCLE_NUM_LOWER +" 次," + num + "次平均时间:" + time + " ms");}
}

测试结果

测试结果如下

结果分析

第一组

10_000_000 次循环拼接,在循环内使用 String 和 StringBuilder 的效率是一样的!为什么呢?

使用 javap -c StringTest.class 反编译查看两个方法编译后的文件:

可以发现 String 方法拼接字符串编译器优化后使用的就是 StringBuilder、因此用例1 和用例2 的效率是一样的。

第二组

第二组的结果就是大家喜闻乐见的了,由于 10_000_000 次循环String 拼接实在太慢所以我采用了 10_000 次拼接来分析。

分析用例3:虽然编译器会对 String 拼接做优化,但是它每次在循环内创建 StringBuilder 对象,在循环内销毁。下次循环他有创建。相比较用例4在循环外创建,多了 n 次 new 对象、销毁对象的操作、n - 1 次将 StringBuilder 转换成 String 的操作 。效率低也是理所应当了。

扩展

第一组的测试还有一种写法:

    /*** 循环内 使用 StringBuilder 拼接字符串,一次循环后销毁*/public static void useStringBuilderOut(){StringBuilder sb = new StringBuilder();for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {
//            sb.setLength(0);sb.delete(0, sb.length());String s = sb.append(str1).append(i).append(str2).append(i).append(str3).append(i).append(str4).toString();}}

循环外创建 StringBuilder 每次循环开始的时候清空 StringBuilder 的内容然后拼接。这种写法无论使用 sb.setLength(0); 还是 sb.delete(0, sb.length()); 效率都比直接在循环内使用 String / StringBuilder 慢。奈何才疏学浅我一直想不明白为什么他慢。我猜测是 new 对象的速度比重置长度慢,于是这样测试了以下:

    public static void createStringBuider() {for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {StringBuilder sb = new StringBuilder();}}public static void cleanStringBuider() {StringBuilder sb = new StringBuilder();for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {sb.delete(0, sb.length());}}

但是结果是 cleanStringBuider 更快。

结论

编译器会将 String 拼接优化成使用 StringBuilder,但是还是有一些缺陷的。主要体现在循环内使用字符串拼接,编译器不会创建单个 StringBuilder 以复用

对于多次循环内拼接一个字符串的需求:StringBuilder 很快,因为其避免了 n 次 new 对象、销毁对象的操作,n - 1 次将 StringBuilder 转换成 String 的操作

StringBuilder 拼接不适用于循环内每次拼接即用的操作方式。因为编译器优化后的 String 拼接也是使用 StringBuilder 两者的效率一样。后者写起来还方便...

最后,再附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,笔者这几年及春招的总结,github 1.5k star,拿去不谢!
下载方式1. 首先扫描下方二维码2. 后台回复「Java面试」即可获取

StringBuider 的效率一定高吗?要看你怎么使用相关推荐

  1. dubbo provider异步_Dubbo支持什么协议?与SpringCould相比它为什么效率要高一些?

    推荐学习 消息中间件合集:MQ(ActiveMQ/RabbitMQ/RocketMQ)+Kafka+笔记 肝了30天,整出这份[分布式宝典:限流+缓存+通讯],秋招跳槽有望 一箭双雕!Alibaba架 ...

  2. 这些天学C++到学ROS,都感觉视频教程效果好些。效率也高些,相比于单自己看书而言。

    这些天学C++到学ROS,都感觉视频教程效果好些.效率也高些,相比于单自己看书而言. .

  3. dcdc芯片效率不高的原因_研学丨燃料电池车的典型效率及能耗

    燃料电池的一大优势是高效率,能够更高效的利用能源.现在燃料电池车的研发已经持续了相当长一段时间(世界上第一辆燃料电池车为1966年通用的Electrovan),燃料电池车也迭代了许多,那么燃料电池车的 ...

  4. SQL优化——IN和EXISTS谁的效率更高

    .点击上方"蓝字" 关注我们,享更多干货! IN和EXISTS被频繁使用在SQL中,虽然作用是一样的,但是在使用效率谁更高这点上众说纷纭.下面我们就通过一组测试来看,在不同场景下, ...

  5. 面试java想要高工资的看这里

    知识储备的重要性 最近在准备一些java面试资料的时候,在网上寻找到的都是一些基础的面试,在找寻无果后,决定自己编排一篇java4-5年所需要的技术知识点,帮助大家梳理一下知识点,以更好的提高自己.相 ...

  6. 一文带你彻底搞懂i++和++i的区别,谁的效率更高?

    作者简介:Codebowl靓仔,学妹的工具人,C++开发误入数据开发,梦想30岁退休的靓仔就是我啦. i++和++i对于初学者来说,一直是一个特别容易搞混的内容,相信很多人现在也没有完全搞清(作者初学 ...

  7. 小程序 const moment = require('moment')_有C语言程序员说,使用移位操作代替乘除运算效率更高,真的吗?...

    在C语言程序开发中,一些移位操作似乎可以达到与乘除法操作一样的效果.例如,4>>1 等于 2,此时右移一位相当于除以 2.类似的,2<<1 等于 4,此时左移一位相当于乘以 2 ...

  8. java版铁傀儡刷新机制,我的世界:新版村庄的铁傀儡数量都快赶上村民了?刷新效率很高!...

    在沙盒游戏我的世界中,铁傀儡一直以来都是村庄和村民最忠诚的守护者,它们的创作灵感来自天空之城,平时还会给小村民送花,一旦发现其他生物欺负村民就会被它们视为攻击目标,相信有不少的熊孩子玩家曾经都体验过铁 ...

  9. 为什么总感觉团队工作效率不高?如何提高工作效率?

    本文首发于[唐虞阁]微信公众号,转载需注明来源,谢谢! 今天,笔者将要帮各位老板/管理者解决管理的头号难题:为什么总感觉团队工作效率不高? 一.看不见的工作效率 可以说,普天之下几乎没有哪个老板会认为 ...

最新文章

  1. jquery学习(3)--高级选择器
  2. html块级元素对齐方式,块级元素的三种垂直水平居中的方法
  3. Hudson-ci/Installing Hudson Windows Service---官方文档
  4. 双12来了!揭秘秒杀剁手背后的云数据库PolarDB!
  5. 【渝粤题库】广东开放大学 社会学基础 形成性考核
  6. 基于java的OA报名与审核管理系统的设计与实现(含源文件)
  7. 一个资深系统管理员的O2O实践(三)
  8. Vista忘记密码如何登录?
  9. php 获取所有子目录名,php读取目录及子目录下所有文件名的方法,_PHP教程
  10. 每天一道剑指offer-数组中出现次数超过一半的数字
  11. sublime双击选中$
  12. HTTP协议简单概述
  13. windows:查询本机ip地址方法
  14. Windows Server 2016-Win Ser 2016已删减内容
  15. JAVA实验三(南邮)
  16. mysql 检索结果排序方式_MySQL--排序检索数据(ORDER BY)
  17. 从零开始写JavaScript框架
  18. Spring Boot缓存实战 EhCache
  19. Matlab实现 把.tdms文件转换成.mat文件,并读取分割成等长信号数据集
  20. freemind中文方框解决

热门文章

  1. linux ifconfig 命令详解
  2. mysql check exist_mysql – 使用多个EXIST进行查询
  3. c++新特性11 (12)weak_ptr类定义
  4. python 语言教程(4)元组
  5. Harbor2.2.1配置(trivy扫描器、镜像签名)
  6. 【Opencv实战】“一岁年龄一岁心,匆匆岁月不由人“这款年龄检测机等你来(附源码)
  7. 这人说的有意思,哈 哈
  8. 导入表注入原理和C语言实现
  9. JUSTCTF校赛安卓wp
  10. 2020-12-3(ESP定律脱壳理解)