Java:String concat vs StringBuilder - 优化了,我该怎么办?我该、String、Java、concat

2023-09-07 02:03:12 作者:你牵我手回家

在 this answer 中,它说(暗示)字符串连接无论如何都优化为 StringBuilder 操作,所以当我写我的代码,有什么理由在源代码中编写 StringBuilder 代码吗?请注意,我的用例与 OP 的问题不同,因为我正在连接/附加数十万行.

In this answer, it says (implies) that String concatenation is optimised into StringBuilder operations anyway, so when I write my code, is there any reason to write StringBuilder code in the source? Note that my use case is different from the OP's question, as I am concatenating/appending hundreds-thousands of lines.

为了让自己更清楚:我很清楚它们之间的差异,只是我不知道是否值得真正编写 StringBuilder 代码,因为它的可读性较差,而且它的表亲,String 类,应该是无论如何都会在编译过程中自动转换.

To make myself clearer: I am well-aware about the differences of each, it's just that I don't know if it's worth actually writing StringBuilder code because it's less readable and when its supposedly slower cousin, the String class, is converted automagically in the compilation process anyway.

推荐答案

我认为 StringBuilder+ 的使用真的取决于你使用它的上下文.

I think the use of StringBuilder vs + really depends on the context you are using it in.

一般使用 JDK 1.6 及以上版本的编译器会自动使用 StringBuilder 将字符串连接在一起.

Generally using JDK 1.6 and above the compiler will automatically join strings together using StringBuilder.

String one = "abc";
String two = "xyz";
String three = one + two;

这会将字符串三编译为:

String three = new StringBuilder().append(one).append(two).toString();

这非常有帮助,并为我们节省了一些运行时间.然而,这个过程并不总是最优的.举个例子:

This is quite helpful and saves us some runtime. However this process is not always optimal. Take for example:

String out = "";
for( int i = 0; i < 10000 ; i++ ) {
    out = out + i;
}
return out;

如果我们编译成字节码,然后反编译生成的字节码,我们会得到类似的结果:

If we compile to bytecode and then decompile the bytecode generated we get something like:

String out = "";
for( int i = 0; i < 10000; i++ ) {
    out = new StringBuilder().append(out).append(i).toString();
}
return out;

编译器已经优化了内部循环,但肯定没有做出最好的优化.为了改进我们的代码,我们可以使用:

The compiler has optimised the inner loop but certainly has not made the best possible optimisations. To improve our code we could use:

StringBuilder out = new StringBuilder();
for( int i = 0 ; i < 10000; i++ ) {
    out.append(i);
}
return out.toString();

现在这比编译器生成的代码更优化,因此在需要高效代码的情况下,肯定需要使用 StringBuilder/StringBuffer 类编写代码.当前的编译器不擅长处理循环中的连接字符串,但是这在未来可能会改变.

Now this is more optimal than the compiler generated code, so there is definitely a need to write code using the StringBuilder/StringBuffer classes in cases where efficient code is needed. The current compilers are not great at dealing concatenating strings in loops, however this could change in the future.

您需要仔细查看需要手动应用 StringBuilder 的位置,并尝试在不会降低代码可读性的地方使用它.

You need to look carefully to see where you need to manually apply StringBuilder and try to use it where it will not reduce readability of your code too.

注意:我使用 JDK 1.6 编译代码,并使用 javap 程序反编译代码,该程序会输出字节码.它相当容易解释,并且在尝试优化代码时通常是一个有用的参考.编译器确实会在幕后更改您的代码,所以看看它做了什么总是很有趣!

Note: I compiled code using JDK 1.6, and and decompiled the code using the javap program, which spits out byte code. It is fairly easy to interpret and is often a useful reference to look at when trying to optimise code. The compiler does change you code behind the scenes so it is always interesting to see what it does!