如何拼接字符串-探究“+号拼接”/“StringBuilder”在不同场景下的效率问题

news2025/7/21 10:53:11

拼接字符串,在程序开发中很常见也很常用,大家都会:

+号拼接

String.concat(String str)

StringBuffer / StringBuilder

但这里今天主要探究“+号拼接”,“StringBuilder”在不同场景下的效率问题不都说 StringBuilder 在处理字符串拼接上效率要强于 String(+号拼接),但有时候我们的理解可能会存在一定的偏差。 最近我在研究数据导入导出效率的时候,发现自己以前对 StringBuilder 的部分理解是错误的。后来通过实践测试 + 查代码找原理 的方式搞清楚了这块的逻辑。现在将过程分享给大家。


测试用例

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

  • 第一种就是每次循环将对象中的几个字段拼接成一个新字段,再赋值给对象。例如,给不同的权益数据list对象model的跳转url拼接相同参数uid。

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

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

第一组:在每次 For 循环中拼接字符串,即拼即用、用完即毁。分别使用 String(+号拼接) 和 StringBuilder 拼接。

/**

* 循环内 String 拼接字符串,一次循环后销毁

*/

public static void useString() {

for (int i = 0; i < CYCLE_NUMBER1; i++) {

String str = str1 + i + str2 + i + str3 + i + str4;

}

}

/**

* 循环内 使用 StringBuilder 拼接字符串,一次循环后销毁

*/

public static void useStringBuilder() {

for (int i = 0; i < CYCLE_NUMBER1; 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_NUMBER2; i++) {

str += str1 + str2 + str3 + str4 + i;

}

}

/**

* 多次循环拼接成一个字符串 用 StringBuilder

*/

public static void useStringBuilderSpliceOneStr() {

StringBuilder sb = new StringBuilder();

for (int i = 0; i < CYCLE_NUMBER2; i++) {

sb.append(str1).append(str2).append(str3).append(str4).append(i);

}

}

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

public static int executeSometime(int type, int num) throws InterruptedException {

Thread.sleep(2000);

int sum = 0;

for (int i = 0; i < num + 10; i++) {

long begin = System.currentTimeMillis();

switch (type) {

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 > 10) {

sum += (end - begin);

}

}

return sum / num;

}

主测试方法

public class StringBuilderStringTest {

public static final int CYCLE_NUMBER1 = 10_000_000;

public static final int CYCLE_NUMBER2 = 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_NUMBER1 + " 次," + num + "次平均时间:" + time + " ms");

time = executeSometime(2, num);

System.out.println("StringBuilder拼接 " + CYCLE_NUMBER1 + " 次," + num + "次平均时间:" + time + " ms");

time = executeSometime(3, num);

System.out.println("String拼接单个字符串 " + CYCLE_NUMBER2 + " 次," + num + "次平均时间:" + time + " ms");

time = executeSometime(4, num);

System.out.println("StringBuilder拼接单个字符串 " + CYCLE_NUMBER2 + " 次," + num + "次平均时间:" + time + " ms");

}

}

测试结果

结果分析

第一组

10_000_000 次循环拼接,在循环内使用 String(+号拼接)和 StringBuilder 的效率几乎是一样的,而且使用String(+号拼接)的效率貌似还高一点!为什么呢?

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

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

第二组

第二组的结果就是大家预期的了,由于 10_000_000 次循环String(+号拼接)拼接实在太慢,也心疼我的电脑呼呼运行,所以我采用了 10_000 次拼接来分析,也能说明问题。

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

同样从反编译查看两个方法编译后的文件也能看出来:


最后结论

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

  • 第一种情况字符串即拼接即用需求用String效率更快一些。每次循环将对象中的几个字段拼接成一个新字段,再赋值给对象。StringBuilder 拼接不适用于循环内每次拼接即用的操作方式。因为编译器优化后的 String(+号拼接)拼接也是使用 StringBuilder 两者的效率一样。但String写起来还更方便。

  • 第二种情况多次循环内拼接一个字符串,最后再用串的需求用 StringBuilder 效率更快一些。在循环外创建一个字符串对象,每次循环向该字符串拼接新的内容。循环结束后得到拼接好的字符串。因为其避免了 n 次 new 对象、销毁对象的操作,n - 1 次将 StringBuilder 转换成 String 的操作。

  • 效率诚如上面分析的,但是很遗憾得玩告诉你,阿里巴巴在他们的规范里面之处不建议在 for 循环里面使用 “+” 进行字符串的拼接。这里的不建议,其实就是不允许的意思,只是人家说的比较委婉而已。现在问题来了,以上的这么多方法都好用,怎么选?

(1)不涉及循环的,就是那种很简单的那种拼接,就用 + ,简单方便 ;

(2)非循环体中的字符串拼接,若只是两个字符串拼接,推荐使用concat。

(3)涉及到循环的,比如说 for 的,可以考虑使用 StringBuilder , 要求线程安全的就选择 StringBuffer ;

(4)有 List 这种的,StringJoiner 不免是一个更好的选择。

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

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

相关文章

保持超低温环境新方法:功耗降至十分之一!

&#xff08;图片来源&#xff1a;网络&#xff09;量子比特是量子计算机的主要构建部分&#xff0c;然而热量会导致量子比特容易出错&#xff0c;因此量子系统通常保存在超低温稀释制冷机内&#xff0c;可以将温度保持在绝对零度&#xff08;−273.15℃&#xff09;以上。但是…

消费复苏迎“春”暖,服装行业如何开启“狂飙”模式?

2023年开年前2个月&#xff0c;全国多地消费市场的“热度”一直在持续上涨&#xff0c;商场、餐馆、娱乐场所等消费市场人气旺盛&#xff0c;消费复苏的“暖”意十足&#xff0c;一幕幕“忙”起来、“热”起来的场景&#xff0c;让各行各业的商家都对未来充满了期待与信心。在消…

基于SpringBoot的外卖项目的优化

基于SpringBoot的外卖项目的优化1、缓存优化1.1、缓存短信验证码问题分析代码改造1.2、缓存菜品数据实现思路1.3、Spring Cache介绍常用注解CachePutCacheEvictCacheable使用方式1.4、缓存套餐数据实现思路代码改造2、读写分离2.1、主从复制存在的问题介绍配置配置主库--master…

获取浏览器硬件资源的媒体数据(拍照、录音、录频、屏幕共享)

目录一、window.navigator 对象包含有关访问者浏览器的信息取二、MediaDevices1.使用麦克风2.使用摄像头&#xff08;和音频一样&#xff09;3.拍照4.录屏三、MediaRecorder(录制,可录制音频视屏)一、window.navigator 对象包含有关访问者浏览器的信息取 <!DOCTYPE html>…

YZRJ面试

面试过程目录概述需求&#xff1a;设计思路实现思路分析1.自我介绍之类的2.http 和https 协议的区别3.进程和线程的区别4.vm 安装的nginx 和Mysql5.评价拓展实现参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full bu…

自然语言处理(NLP)之求近义词和类比词<MXNet中GloVe和FastText的模型使用>

这节主要就是熟悉MXNet框架中的两种模型&#xff1a;GloVe和FastText的模型(词嵌入名称)&#xff0c;每个模型下面有很多不同的词向量&#xff0c;这些基本都来自wiki维基百科和twitter推特这些子集预训练得到的。我们只需要导入mxnet.contrib中的text模块即可&#xff0c;这里…

模拟百度翻译-课后程序(JAVA基础案例教程-黑马程序员编著-第六章-课后作业)

【案例6-5】 模拟百度翻译 【案例介绍】 1.任务描述 大家对百度翻译并不陌生&#xff0c;本案例要求编写一个程序模拟百度翻译。用户输入英文之后搜索程序中对应的中文&#xff0c;如果搜索到对应的中文就输出搜索结果&#xff0c;反之给出提示。本案例要求使用Map集合实现英…

C/C++开发,无可避免的内存管理(篇一)-约束好跳脱的内存

一、养成内存管理好习惯 1.1 养成动态对象创建、调用及释放好习惯 开发者手动接管内存分配时&#xff0c;必须处理这两个任务。分配原始内存时&#xff0c;必须在该内存中构造对象&#xff1b;在释放该内存之前&#xff0c;必须保证适当地撤销这些对象。如果你的项目是c项目&am…

windows、linux系统设置404教程(适用虚拟主机)

设置一个好的自定义错误页面&#xff0c;可以增加网站的收录&#xff0c;挽留住一些可能因打不开的页面而放弃的客户&#xff0c;我司虚拟主机特别提供了自定义错误页面设置&#xff0c;包括404错误在内的所有自定义错误都可以设置。 linux系统设置方法&#xff1a; 第一步:在…

mysql 内存架构

1. 背景 从 innodb 的整体架构中可以知道 innodb 的内存架构中分为 buffer pool 缓存区, change pool 修改缓冲区, adaptive hash index 自适应哈希索引, 和 log buffer 日志缓冲区. 2. buffer pool buffer pool 是用于缓冲磁盘页的数据&#xff0c;mysql 的80%的内存会分配给…

通过cfssl自签证书https证书

背景 公司内部自建Web服务&#xff0c;通过自签CA&#xff0c;然后签发https证书 工具地址: GitHub - cloudflare/cfssl: CFSSL: Cloudflares PKI and TLS toolkit 使用步骤: 1. 在release页面中下载最新的二进制包&#xff0c;我使用的是1.5的解压并重命名二进制文件 tar…

Idea集成码云

1&#xff1a;Idea集成码云1.1&#xff1a;IDEA安装码云插件【第一步】Idea 默认不带码云插件&#xff0c; 我们第一步要安装 Gitee 插件。如图所示&#xff0c; 在 Idea 插件商店搜索 Gitee&#xff0c;然后点击右侧的 Install 按钮。安装成功后&#xff0c;重启 Idea。Idea 重…

复旦团队发布国内首个模型MOSS 类ChatGPT

复旦团队发布国内首个模型MOSS 类ChatGPT 首先看到这个标题&#xff0c;还有这个名字&#xff0c;我是正经&#xff08;zhen jing&#xff09;的 &#xff08;bu shi 流浪地球&#xff1f;550W&#xff1f;不了解的可以把550W倒过来写&#xff0c;就懂了 看到新闻里的一些图…

Interview系列 - 07 Java | 集合的快速失败和安全失败机制 | 迭代器类源码 | CopyOnWriteArrayList

文章目录1. 集合的快速失败 (fail-fast)1. 使用增强for遍历集合并使用ArrayList的 remove() 方法删除集合元素2. 使用 forEach 遍历集合并使用ArrayList的 remove() 方法删除集合元素3. 使用迭代器遍历集合并使用ArrayList的 remove() 方法删除集合元素4. 使用迭代器遍历集合并…

人脑脊液的代谢组学研究—标识恶性神经胶质瘤的特征

百趣代谢组学分享&#xff0c;脑疾病病人的脑脊液&#xff08;CSF&#xff09;通常用来诊断和监测研究&#xff0c;但是恶性胶质瘤病人脑脊液组成的变化很少被人们所知。该研究作者建立了靶向代谢组学分析方法&#xff0c;采用SRM监测模式&#xff0c;使用正负离子切换的方法在…

MySQL实战之深入浅出索引(上)

1.前言 提到数据库&#xff0c;大家肯定会想到数据库的索引&#xff0c;很多人都知道索引是为了提高查询效率的&#xff0c;那么今天我就给大家讲一下&#xff0c;什么是索引&#xff0c;索引的数据结构是什么&#xff0c;索引是如何工作的。 因为索引的内容比较多&#xff0…

大数据应用要经得起考验,不可盲目跟风_光点科技

一项大数据应用&#xff0c;如果不是经得起推敲的&#xff0c;那就值得怀疑它是不是优秀的大数据应用&#xff0c;是不是有可利用的价值&#xff0c;是不是值得将人力物力财力花费在其中。所以&#xff0c;必须对大数据应用进行必要的筛选&#xff0c;做一定的检验之后才可以做…

vegfr2药物|适应症|市场销售数据-上市药品前景分析

癌症作为人类身体健康的主要威胁&#xff0c;其高死亡率一直是人类死亡的主要原因。尽管人类为控制癌症付出了巨大的努力&#xff0c;然而癌症的发病率和死亡率还是在高速增长。而肺癌、结直肠癌、肝癌和乳腺癌等被认为是癌症死亡的主要因素。而根据科研人员发现&#xff0c;癌…

JavaScript HTML DOM 简介

文章目录JavaScript HTML DOM 简介HTML DOM (文档对象模型)HTML DOM 树查找 HTML 元素通过 id 查找 HTML 元素通过标签名查找 HTML 元素通过类名找到 HTML 元素下面我们将学到如下内容JavaScript HTML DOM 简介 通过 HTML DOM&#xff0c;可访问 JavaScript HTML 文档的所有元素…

高清无码的MP4如何采集?python带你保存~

前言 大家早好、午好、晚好吖 ❤ ~ 又是我,我又来采集小姐姐啦~ 这次我们采集的网站是(看下图): 本文所有模块\环境\源码\教程皆可点击文章下方名片获取此处跳转 话不多少,我们赶快开始吧~ 第三方模块: requests >>> pip install requests 如果安装python第三方模块…