小程序循环里做字符串拼接_昨天还在for循环里写加号拼接字符串的那个同事,今天已经不在了...

3c55dd9d582ff723a1c054cabfc55d67.png

引言

都说 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");    }}

测试结果

69785a40cd56d482e8dcc35759a968b3.png

结果分析

第一组

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

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

5162100dbb2f6577e6be81b358b2663e.png

可以发现 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 两者的效率一样。后者写起来还方便...

作者:后青春期的 Keats

来源:cnblogs.com/keatsCoder/p/13212289.html

最近小伙伴们找我要一些 MySQL基础资料,于是我翻箱倒柜,把这份阿里大牛总结的 MySQL 归纳笔记找出来,免费共享给大家!

32c195d678649f2ef558637c215f7a5b.png

资源,怎么领取?加我微信,备注:mysql(一定要备注:mysql)否则不会自动通过766f06c127530e57e0ff4bf6c3466e69.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【T-SQL系列】新的排序函数

【T-SQL系列】新的排序函数 原文:【T-SQL系列】新的排序函数如&#xff1a;ROW_NUMBER、RANK、DENSE_RANK三个分析函数都是按照col1分组内从1开始排序 ROW_NUMBER() 是没有重复值的排序(即使两天记录相等也是不重复的)&#xff0c;可以利用它来实现分页 DENSE_RANK() 是连续排序…

java mysql修改表结构字段_【开发技术】java+mysql 更改表字段的步骤

1).首先通过SQL更改MYSQL库中的表结构(下面是一些例子)ALTER TABLE illegalactivate ADD macethaddress varchar(250) NOT NULL;Alter TABLE illegalactivate drop primary key;ALTER TABLE illegalactivate ADD CONSTRAINT PK_illegalactivate PRIMARY KEY ( macaddress…

阿里云rds升级mysql8_为更强大而生的开源关系型数据库来了!阿里云RDS for MySQL 8.0 正式上线!...

2019年5月29日15时&#xff0c;阿里云RDS for MySQL 8.0正式上线&#xff0c;使得阿里云成为紧跟社区步伐&#xff0c;发布MySQL最新版本的云厂商。RDS for MySQL 8.0 产品是阿里云推出的 MySQL 系列云产品之一&#xff0c;使用完全兼容 MySQL 8.0 的阿里云 AliSQL 8.0 分支&am…

mysql gtid 还是pxc_记一次 PXC 集群拆分引发的思考

原标题&#xff1a;记一次 PXC 集群拆分引发的思考作者简介冷正磊2018年2月加入去哪儿网 DBA 团队&#xff0c;主要负责机票业务的 MySQL 和 Redis 数据库的运维管理工作&#xff0c;以及数据库自动化运维平台部分功能的开发工作&#xff0c;对数据库技术具有浓厚兴趣&#xff…

java_IO总结(一)

所谓IO&#xff0c;也就是Input与Output的缩写。在java中&#xff0c;IO涉及的范围比较大&#xff0c;这里主要讨论针对文件内容的读写 其他知识点将放置后续章节&#xff08;我想&#xff0c;文章太长了&#xff0c;谁都没耐心翻到最后&#xff09; 对于文件内容的操作主要分为…

ocsng mysql connection problem_OCSNG 介绍及其工作原理

OCSNG部署&#xff1a;http://wowking.blog.51cto.com/1638252/994441OCSNG 是什么呢&#xff1f;OCSNG就是Open Computer and Software Inventory Next Generation是一款免费软件&#xff0c;它使用户能够盘点网络工程师的IT资产。OCS-NG收集有关运行OCS客户端程序(“OCS Inve…

hdu--5135--贪心

尽量选边数大的3根木棍来组成一个三角形 一直到无法选取为止 这边计算三角形面积 还是用 海伦公式比较方便 1 #include <iostream>2 #include <algorithm>3 #include <cmath>4 #include <cstring>5 #include <iomanip>6 using namespace std;7 …

【Daily Scrum】12-08

因为TFS的一些问题&#xff0c;到现在一直都看不了Sprint 3的burndown and burn rate. 今天的scrum发现这个Sprint期间大家组里的事情都比较多&#xff0c;不过大家还是有很努力地在晚上和周末来完成ASC Master的任务&#xff0c;辛苦~ Member Today’s WorkTomorrow’s WorkFe…

java 字符串转成图片_java 转换图片为字符串,将字符串转换成图片显示

java 转换图片为字符串&#xff0c;将字符串转换成图片显示&#xff0c;该方法只适用于比较小的图片传输&#xff0c;50K以内&#xff1a;try{// 将图片转换成字符串File imgFile new File("f:\\Vista.png");FileInputStream fis new FileInputStream( imgFile );b…

转移指令检测题9

补全编程&#xff0c;利用loop指令&#xff0c;实现在内存2000H段中查找第一个值为0的字节&#xff0c;找到后&#xff0c;将它的偏移地址存储在DX中 assume cs:code code segment start:mov ax,2000h mov ds,ax mov bx,0 s: mov cl,[bx] mov ch,0 inc cx ;此处为要…

c语言 java append_C++中append函数的用法和函数定义。谢谢!

展开全部要想使用标准C中string类&#xff0c;必须要包含#include // 注意是&#xff0c;不62616964757a686964616fe78988e69d8331333339663434是&#xff0c;带.h的是C语言中的头文件using std::string;using std::wstring;或using namespace std;下面你就可以使用string/wstr…

很好用的程序员在线画图软件

今天向大家推荐一个很好用的在线画图软件&#xff1a;今天向大家推荐一个很好用的在线画图软件&#xff1a;今天向大家推荐一个很好用的在线画图软件&#xff1a;&#xff08;重要的事情说三篇&#xff09;连接地址如下&#xff1a;https://www.processon.com/i/55e3195de4b0df…

java breakpoint_java断点

第一步&#xff1a;用firefox运行程序&#xff0c;当点击保存&#xff0c;提示保存失败后&#xff0c;启动firebug通过请求找到addNew.ezt出现错误&#xff0c;在eztnews.xml里通过ctrlF查找找到请求执行的类和方法找到NewsAction类的doAddNew方法然后在通过找到NewsActions.ja…

OC之ARC环境中的循环strong问题

2019独角兽企业重金招聘Python工程师标准>>> main.m文件&#xff1a; #import <Foundation/Foundation.h> #import "Person.h" #import "Dog.h"int main() {Person *p [[Person alloc] init];Dog *d [[Dog alloc] init];p.dog d;d.per…

Android自定义view之圆形进度条

本节介绍自定义view-圆形进度条思路&#xff1a;根据前面介绍的自定义view内容可拓展得之&#xff1b;1&#xff1a;新建类继承自View2&#xff1a;添加自定义view属性3&#xff1a;重写onDraw(Canvas canvas)4&#xff1a;实现功能下面上代码1.自定义view代码&#xff1a; pub…

java二级考试备考_2017计算机二级考试《JAVA》备考测试题「带答案」

2017计算机二级考试《JAVA》备考测试题「带答案」为确保同学们将所涉及的考点全面复习到位&#xff0c;让大家充满信心的步入考场&#xff0c;以下是百分网小编搜索整理的一份计算机二级考试《JAVA》备考测试题【带答案】&#xff0c;供参考练习&#xff0c;希望对大家有所帮助…

java流类图结构_java学习之IO流(学习之旅,一)

个人在学习IO流的时候看到如下所示java 流类图结构的时候&#xff0c;我的感想是&#xff0c;这么多处于蒙的状态。Java流类图结构这么多&#xff0c;没有分类不好学&#xff0c;那我们就慢慢一口一口的吃&#xff0c;这样每天学习一点就好了&#xff0c;其实很多类并不是常用的…

php 安装xdebug扩展

php 扩展获取地址 http://pecl.php.net/package/ 编译安装的过程 wget http://pecl.php.net/get/xdebug-2.2.2.tgz tar -zxvf xdebug-2.2.2.tgz cd xdebug-2.2.2/ /data/klj/php/bin/phpize ./configure --enable-xdebug --with-php-config/data/klj/php/bin/php-config mak…

拨打电话 java_简单拨打电话程序

众所周知,对于一个手机,能拨打电话是其最重要也是最常用的一个功能.而在Android里是怎么样实现拨打电话的程序呢?我在这里写了一个简单的拨打电话的Demo,供大家参考.一共分为5个步骤.Step 1:新建一个Android工程,命名为phoneCallDemo.Step 2:设计程序的界面,打开main.xml把内容…

WPF01(xaml)

XAML&#xff1a;&#xff08;转自http://www.cnblogs.com/huangxincheng/archive/2012/06/17/2552511.html&#xff09; <Window x:Class"WpfApplication1.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"…