本文收发地址 https://h89.cn/archives/115.html

1. 问题背景

在日常Java开发中,我们经常会遇到字符串拼接的场景。传统观点认为StringBuilder的性能优于String直接拼接,但最近在使用Intellij IDEA时,IDE却建议将StringBuilder替换为String,这是为什么呢?

Intellij建议

这个问题在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

从字节码可以看出:

  1. String拼接在JDK 9+版本中使用了invokedynamic指令,底层优化为类似StringBuilder的实现
  2. StringBuilder需要创建对象、多次调用append方法,最后还要toString

4. 最佳实践建议

根据以上分析,我们可以得出以下实践建议:

  1. 简单字符串拼接

    • 使用String的+操作符
    • 代码更简洁,可读性更好
    • JDK已经在底层做了优化
  2. 循环中的字符串拼接

    • 优先使用StringBuilder
    • 避免在循环中使用String的+操作符
    • StringBuilder可以有效减少中间对象的创建
  3. 大量文本处理

    • 使用StringBuilder或StringBuffer
    • 预估容量并指定初始大小
    • 考虑线程安全需求选择StringBuffer

5. 总结

  1. Intellij建议使用String替换StringBuilder的原因是合理的,在简单拼接场景下确实没必要使用StringBuilder
  2. 在循环累加等场景下,StringBuilder的性能优势仍然明显
  3. 编码时应根据具体场景选择合适的实现方式

如果您觉得本文对您有帮助,欢迎点赞收藏,也欢迎在评论区留言讨论。


本文链接:Intellij建议用String替换StringBuilder - https://h89.cn/archives/115.html

版权声明:原创文章 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接和本声明。

标签: StringBuilder

评论已关闭