大数跨境
0
0

Java中8种字符串拼接方式,性能很意外

Java中8种字符串拼接方式,性能很意外 Spring全家桶实战案例
2025-01-02
0
导读:Java中8种字符串拼接方式,性能很意外

最新实战案例锦集:《Spring Boot3实战案例合集》持续更新,每天至少更新一篇文章,订阅后将赠送文章最后展示的所有MD文档(学习笔记)。

【重磅发布】《Spring Boot 3实战案例锦集》PDF电子书现已出炉!

🎉🎉我们精心打造的《Spring Boot 3实战案例锦集》PDF电子书现已正式完成,目前已经有70个案例,后续还将继续更新。文末有电子书目录。

📚📚订阅获取
只需订阅我们的合集点我订阅,即可立即私信我们获取这本珍贵的电子书。轻松拥有Spring Boot 3的实战宝典!

💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。这意味着,随着技术的不断发展和Spring Boot 3的深入应用,我们的电子书也将持续更新,确保您始终掌握最前沿、最实用的技术知识。

🔥🔥精彩内容不容错过
《Spring Boot 3实战案例锦集》汇聚了众多精心挑选的实战案例,旨在帮助您快速掌握Spring Boot 3的核心技术和实战技巧。无论您是初学者还是有一定经验的开发者,都能从中受益匪浅。

💌💌如何获取
请立即订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

现在就订阅合集


环境:SpringBoot3.2.5



1. 简介

在开发中,字符串拼接是非常常见的操作,广泛应用于日志记录、数据处理、用户界面生成等场景。然而,不同的字符串拼接方式在性能上有着显著的差异,这一点往往被开发人员忽视。本文将详细介绍 Java 中的 8 种字符串拼接方式,并通过性能测试揭示这些方法的实际表现,结果令人意外。

Java中可以使用如下8种方式进行字符串的拼接:

  1. "+"操作符

  2. String#concat方法

  3. String#join方法

  4. String#format方法

  5. Stream流方式

  6. StringBuffer

  7. StringBuilder

  8. StringJoiner

     

我们将通过JMH进行性能的测试,所以如果你对JMH还不熟悉的,你可以查看下面这篇文章:

Java高级开发必须掌握JMH进行性能测试优化

下面我们依次介绍这8中方式;接下来的示例我们都将建立在JMH之上。

2. 实战案例

2.1 "+"操作符

这是最简单的方法,也是我们可能最熟悉的一种。它可以使用加号(+)运算符来连接字符串字面量、变量或者二者的组合:

@Benchmarkpublic void plusOperator(Blackhole hole) {  String str1 = "Pack";  String str2 = " xxxooo";  String result = str1 + str2;  hole.consume(result);}

2.2 String#concat方法

concat() 方法由 String 类提供,可用于将两个字符串连接在一起。

@Benchmarkpublic void concat(Blackhole hole) {  String str1 = "Pack";  String str2 = " xxxooo";  String result = str1.concat(str2);  hole.consume(result);}

2.3 String#join方法

String.join() 是 Java 8 以后新增的静态方法。它允许使用指定的分隔符连接多个字符串。

@Benchmarkpublic void join(Blackhole hole) {  String str1 = "Pack";   String str2 = " xxxooo";   String result = String.join("", str1, str2);  hole.consume(result);}

2.4 String#format方法

String.format() 用于使用占位符和格式指定符格式化字符串。通过使用实际值替换占位符,可以创建格式化字符串。

@Benchmarkpublic void format(Blackhole hole) {  String str1 = "Pack";   String str2 = " xxxooo";   String result = String.format("%s%s", str1, str2);  hole.consume(result);}

2.5 Stream流

它为在对象集合上执行操作提供了一种富有表现力的方法,并允许我们使用 Collectors.joining() 来集中字符串。

@Benchmarkpublic void stream(Blackhole hole) {  List<String> strList = Arrays.asList("Pack", " xxxooo");  String result = strList.stream().collect(Collectors.joining());  hole.consume(result);}

2.6 StringBuffer

StringBuffer 提供了一个可变的字符序列。它允许对字符串进行动态操作而无需创建新的对象。值得一提的是,它被设计为线程安全的,这意味着它可以被多个线程安全地并发访问和修改。

@Benchmarkpublic void stringBuffer(Blackhole hole) {  StringBuffer buffer = new StringBuffer();  buffer.append("Pack") ;   buffer.append(" xxxooo") ;   String result = buffer.toString() ;  hole.consume(result) ;}

2.7 StringBuilder

StringBuilder 和 StringBuffer 的用途相同。它们之间唯一的区别是 StringBuilder 不是线程安全的,而 StringBuffer 是。在不需要考虑线程安全的单线程场景中,StringBuilder 是非常完美的选择。

@Benchmarkpublic void stringBuilder(Blackhole hole) {  StringBuilder builder = new StringBuilder() ;   builder.append("Pack") ;   builder.append(" xxxooo") ;   String result = builder.toString() ;  hole.consume(result) ;}

2.8 StringJoiner

StringJoiner 是从 Java 8 开始引入的一个新类。它的功能与 StringBuilder 类似,提供了一种使用分隔符连接多个字符串的方式。尽管它与 StringBuilder 有相似之处,但 StringJoiner 也不是线程安全的。

@Benchmarkpublic void stringJoiner(Blackhole hole) {  StringJoiner joiner = new StringJoiner("");  joiner.add("Pack") ;  joiner.add(" xxxooo") ;  String result = joiner.toString() ;  hole.consume(result) ;}

以上我们简单的介绍了每一种字符串拼接的使用。

3. 性能测试

接下来,我们通过JMH进行性能的测试,首先我们在类上添加如下的注解:

// 预热1s钟,预热3次@Warmup(iterations = 3, time = 1)// 启动多少个进程@Fork(value = 1, jvmArgsAppend = {"-Xms512m", "-Xmx512m"})// 指定显示结果(枚举值)@BenchmarkMode(Mode.AverageTime)// 指定显示结果单位(枚举值)@OutputTimeUnit(TimeUnit.NANOSECONDS)// 迭代10次,每次2s@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)public class StringJoinTest {  // 上面8种字符串拼接的方法}

在本示例中,我们将通过main的方式运行,这种方式稍微有点不是特别准确,你可以选择jar的方式。

public static void main(String[] args) throws Exception {  Options options = new OptionsBuilder()    // 你要测试的类    .include(StringJoinTest.class.getSimpleName())    // 启动几个进程    .forks(1).build();  new Runner(options).run();}

最终测试结果如下:

下面是对上面每一列的说明(以第一行concat测试为例说明)

  • Benchmark

    • 说明:基准测试的名称,通常是类名+方法名。

    • 示例:StringJoinTest.concat。

  • Mode

    • 说明:基准测试的模式,常见模式有:

      • avgt:平均时间模式(Average Time),每个操作的平均时间。

      • thrpt:吞吐量模式(Throughput),单位时间内完成的操作次数。

      • sample:采样模式,用于收集详细的统计信息。

      • ss:稳定状态模式,用于评估长时间运行的性能稳定性。

    • 示例:avgt

  • Cnt

    • 说明:迭代次数,即基准测试运行的次数。

    • 示例:10

  • Score

    • 说明:基准测试的主要结果指标。根据模式的不同,这个值的含义也不同。

      • avgt:每个操作的平均时间(秒、毫秒、纳秒等)。

      • thrpt:每秒完成的操作次数(ops/s)。

    • 示例:8.584

  • Error

    • 说明:结果的标准误差(Standard Error),表示结果的不确定性。

    • 示例:0.175

  • Units

    • 说明:结果的单位

    • 示例:ns/op(每操作纳秒)

       

基准测试结果来看,"+"加操作符是最高效的,String#format方法是最慢的。

性能排序

  1. (+)plusOperator:6.154 ± 0.119 ns/op

  2. concat:8.584 ± 0.175 ns/op

  3. stringBuilder:11.560 ± 0.216 ns/op

  4. stringBuffer:12.340 ± 0.150 ns/op

  5. stringJoiner:29.932 ± 0.236 ns/op

  6. join:28.210 ± 0.241 ns/op

  7. stream:34.293 ± 0.284 ns/op

  8. format:409.691 ± 2.941 ns/op

     

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

@Order注解,你理解错了!

不写一行代码通过UI界面配置HTTP接口

Spring Boot + 事务钩子,完美解决事务并发问题

性能提升!Spring Boot使用Guava中3大神技

SpringBoot+Nginx+Lua接口性能提升N倍

基于SpringBoot支持任意文件在线预览

Spring创建AOP代理并非只有@Aspect一种方式

Spring强大的URI操作工具类太方便了

你以为只有Controller一种接口定义方式?详解Web函数式接口

@InitBinder注解会用吗?该如何使用?

【强烈推荐】基于内存和Redis的两级 Java 缓存框架

解锁Spring资源Resource的强大功能,提升开发效率

SpringBoot参数验证@Validated和@Valid分清楚了吗?这些验证细节你知道吗?

Spring一个强大便捷的代理工厂类,你用过吗?

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读7
粉丝0
内容832