最佳实践/性能:将 StringBuilder.append 与 String.concat 混合使用



我试图了解最佳实践是什么以及为什么为不同情况连接字符串文字和变量。例如,如果我有这样的代码

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

这是这样做的方法吗?从这篇文章中,我注意到字符串上的+运算符创建了一个 StringBuilder 的新实例,连接操作数,并返回一个字符串转换,这似乎比仅仅调用 .append() 要多得多;因此,如果这是真的,那么这是不可能的。但是String.concat()呢?对每个串联使用 .append() 是否合适?或者只是为了变量,文字可以附加.concat()

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

处理这些情况的最佳实践和性能的一般规则是什么?我对+的假设是否正确,它真的不应该被使用?

+运算符

String s = s1 + s2

在幕后,这被翻译成:

String s = new StringBuilder(s1).append(s2).toString();

想象一下,如果你在这里有s1 + s2,它会增加多少额外的工作:

stringBuilder.append(s1 + s2)

而不是:

stringBuilder.append(s1).append(s2)

+的多个字符串

值得注意的是:

String s = s1 + s2 + s3 + ... +sN

翻译成:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

String 创建char[]既适合s1又适合s2的数组。将s1s2内容复制到此新阵列。实际上需要比+操作员更少的工作。

StringBuilder.append()

维护在需要时增长的内部char[]阵列。如果内部char[]足够大,则不会创建额外的。

stringBuilder.append(s1.concat(s2))

性能也很差,因为s1.concat(s2)创建了一个额外的char[]数组并将s1s2复制到其中,只是为了将该新数组内容复制到内部StringBuilder char[]

话虽如此,您应该一直使用append()并附加原始字符串(您的第一个代码片段是正确的)。

编译器优化了 + 连接。

所以

int a = 1;
String s = "Hello " + a;

被转化为

new StringBuilder().append("Hello ").append(1).toString();

这里有一个很好的主题来解释为什么你应该使用 + 运算符。

优化由编译器自动完成。

Java2 编译器将自动转换以下内容:

String s = s1 + s2; 

String s = (new StringBuffer()).append(s1).append(s2).toString();

直接取自 Oracle 上的 Java 最佳实践网站。

您应该始终使用 append .

concat创建一个新的字符串,所以它就像我认为+一样。

如果您concat或使用带有 2 个最终字符串的 +,JVM 可以进行优化,因此在这种情况下与执行追加相同。

如果您正好连接两个字符串,请使用 String.concat(通过创建一个适合两个字符串的新字符数组并将两个字符串的字符数组复制到其中来创建一个新的字符串)。

如果您在一行中连接多个(超过两个)字符串,请使用 + 或 StringBuilder.append,这无关紧要,因为编译器将 + 转换为 StringBuilder.append。这适用于多个字符串,因为它维护一个根据需要增长的 char 数组。

如果在多行上连接多个字符串,请创建一个 StringBuilder 并使用 append-方法。最后,当您完成将字符串附加到 StringBuilder 时,请使用它的 .toString()-方法从中创建字符串。对于多行连接,这比第二种方法更快,因为第二种方法会在每行上创建一个新的 StringBuilder,附加字符串,然后转换回 String,而第三种方法只使用一个 StringBuilder 来完成整个过程。

我个人更喜欢Strings.format(),简单易读的单行字符串格式化程序。

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F

使用+运算符是最佳实践,它也简单易读。

Java 语言为字符串提供了特殊支持 串联运算符 (+) ,并将其他对象转换为 字符串。字符串串联是通过 StringBuilder(或 StringBuffer) 类及其追加方法。

正式文件:https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

字节码级别没有区别,我们在那里不会影响效率。在执行字节码级别的情况下,它必须通过调用 append 为 + 的非内联运算符重载方法。然后在汇编语言级别(Java是用C编写的,C生成类似于汇编的程序集,堆栈中将有额外的寄存器调用来存储+方法调用,并且会有额外的推送。(实际上,交叉编译器可能会优化 + 运算符调用,在这种情况下,效率没有区别。

最好有一种方法来提高可读性。 :)

所有答案都非常好且具有解释性。但我觉得探索其他字符串连接技术也会有所帮助 - 番石榴连接器,流,字符串格式等。

有关每种连接技术性能的完整详细信息,java-string-concatenation-哪一种方式是最好的。

简而言之,串联性能因要连接的字符串数量而异。例如 - 要连接 1-10 个字符串,这些技术效果最好 - StringBuilder、StringBuffer 和 Plus Operator。为了连接 100 多个字符串 - Guava Joiner,apache 的 stringsUtils 库也很好用。

请浏览上面的博客。它确实很好地解释了性能效率。

谢谢。

最新更新