文章目录
本文收发地址 https://blog.csdn.net/CSqingchen/article/details/135324313
最新更新地址 https://gitee.com/chenjim/chenjimblog
1. 问题背景
在日常Java开发中,我们经常会遇到字符串拼接的场景。传统观点认为StringBuilder的性能优于String直接拼接,但最近在使用Intellij IDEA时,IDE却建议将StringBuilder替换为String,这是为什么呢?
这个问题在JetBrains社区也引发了热烈讨论:社区讨论链接
2. 性能测试分析
2.1 基础性能测试
让我们通过一个简单的测试来对比String和StringBuilder的性能:
public static void main(String[] args) {
String input = "ABCDEF";
String append = ",AP,";
// 测试String直接拼接
Instant start = Instant.now();
String out = "oo";
for (int i = 0; i < 10000; i++) {
out = input + append;
}
System.out.println(out + Duration.between(start, Instant.now()).toNanos());
// 测试StringBuilder拼接
start = Instant.now();
for (int i = 0; i < 10000; i++) {
StringBuilder sb = new StringBuilder();
out = sb.append(input).append(append).toString();
}
System.out.println(out + Duration.between(start, Instant.now()).toNanos());
}
测试结果:
ABCDEF,AP,2999000
ABCDEF,AP,1999600
从结果可以看出,在简单的字符串拼接场景下,两者的性能差异并不明显。
2.2 循环累加场景测试
在循环累加的场景下,性能差异会更加明显:
// 测试String循环累加
start = Instant.now();
for (int i = 0; i < 10000; i++) {
out = out + i;
}
System.out.println(out.length() + "," + Duration.between(start, Instant.now()).toNanos());
// 测试StringBuilder循环累加
start = Instant.now();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(input).append(append);
}
out = sb.toString();
System.out.println(out.length() + "," + Duration.between(start, Instant.now()).toNanos());
3. 字节码层面分析
通过javap -c abc.class
命令查看字节码,我们可以深入理解两种方式的实现原理:
3.1 String拼接的字节码
38: invokedynamic #31, 0 // InvokeDynamic #0:makeConcatWithConstants
43: astore 4
3.2 StringBuilder的字节码
89: new #51 // class java/lang/StringBuilder
92: dup
93: invokespecial #53 // Method StringBuilder."<init>"
96: astore 6
98: aload 6
100: aload_1
101: invokevirtual #54 // Method StringBuilder.append
104: aload_2
105: invokevirtual #54 // Method StringBuilder.append
108: invokevirtual #58 // Method StringBuilder.toString
从字节码可以看出:
- String拼接在JDK 9+版本中使用了
invokedynamic
指令,底层优化为类似StringBuilder的实现 - StringBuilder需要创建对象、多次调用append方法,最后还要toString
4. 最佳实践建议
根据以上分析,我们可以得出以下实践建议:
-
简单字符串拼接:
- 使用String的
+
操作符 - 代码更简洁,可读性更好
- JDK已经在底层做了优化
- 使用String的
-
循环中的字符串拼接:
- 优先使用StringBuilder
- 避免在循环中使用String的
+
操作符 - StringBuilder可以有效减少中间对象的创建
-
大量文本处理:
- 使用StringBuilder或StringBuffer
- 预估容量并指定初始大小
- 考虑线程安全需求选择StringBuffer
5. 总结
- Intellij建议使用String替换StringBuilder的原因是合理的,在简单拼接场景下确实没必要使用StringBuilder
- 在循环累加等场景下,StringBuilder的性能优势仍然明显
- 编码时应根据具体场景选择合适的实现方式
如果您觉得本文对您有帮助,欢迎点赞收藏,也欢迎在评论区留言讨论。