Java StringBuilder 与 StringWriter 和 PrintWriter 的字符串组装

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2980805/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 15:12:40  来源:igfitidea点击:

String assembly by StringBuilder vs StringWriter and PrintWriter

java

提问by CPerkins

I recently encountered an idiom I haven't seen before: string assembly by StringWriter and PrintWriter. I mean, I know how to use them, but I've always used StringBuilder. Is there a concrete reason for preferring one over the other? The StringBuilder method seems much more natural to me, but is it just style?

我最近遇到了一个我以前从未见过的习语:StringWriter 和 PrintWriter 的字符串组装。我的意思是,我知道如何使用它们,但我一直使用 StringBuilder。是否有具体的理由偏爱一个而不是另一个?StringBuilder 方法对我来说似乎更自然,但它只是风格吗?

I've looked at several questions here (including this one which comes closest: StringWriter or StringBuilder), but none in which the answers actually address the question of whether there's a reason to prefer one over the other for simple string assembly.

我在这里查看了几个问题(包括最接近的一个:StringWriter 或 StringBuilder),但没有一个问题的答案实际上解决了是否有理由在简单的字符串组装中选择一个而不是另一个的问题。

This is the idiom I've seen and used many many times: string assembly by StringBuilder:

这是我见过并多次使用的习语:StringBuilder 的字符串组装:


    public static String newline = System.getProperty("line.separator");
    public String viaStringBuilder () {
       StringBuilder builder = new StringBuilder();
       builder.append("first thing").append(newline);  // NOTE: avoid doing builder.append("first thing" + newline);
       builder.append("second thing").append(newline);
       // ... several things
       builder.append("last thing").append(newline);
       return builder.toString();
    }

And this is the new idiom: string assembly by StringWriter and PrintWriter:

这是新的习惯用法:StringWriter 和 PrintWriter 的字符串组装:


    public String viaWriters() {
       StringWriter stringWriter = new StringWriter();
       PrintWriter printWriter = new PrintWriter(stringWriter);
       printWriter.println("first thing");
       printWriter.println("second thing");
       // ... several things
       printWriter.println("last thing");
       printWriter.flush();
       printWriter.close();
       return stringWriter.toString();
    }

EditIt appears that there is no concretereason to prefer one over the other, so I've accepted the answer which best matches my understanding, and +1ed all the other answers. In addition, I posted an answer of my own, giving the results of the benchmarking I ran, in response to one of the answers. Thanks to all.

编辑似乎没有具体的理由更喜欢一个,所以我接受了最符合我理解的答案,并对所有其他答案+1。此外,我发布了自己的答案,给出了我运行的基准测试的结果,以回应其中一个答案。谢谢大家。

Edit againIt turns out that there isa concrete reason to prefer one (specifically the StringBuilder) over the other. What I missed the first time was the addition of the newline. When you add a newline (as above, as a separate append), it's slightly faster - not hugely, but coupled with the clarity of intent, it's definitely better. See my answer below for the improved timings.

再次编辑事实证明,有一个具体的理由,更喜欢一个(特别是StringBuilder的)比其他。我第一次错过的是添加换行符。当你添加一个换行符(如上,作为一个单独的附加)时,它会稍微快一点 - 不是很大,但是加上意图的清晰度,它肯定会更好。有关改进的时间安排,请参阅下面的答案。

采纳答案by Stephen C

Stylistically, the StringBuilderapproach is cleaner. It is fewer lines of code and is using a class that was specifically designed for the purpose of building strings.

从风格上讲,这种StringBuilder方法更简洁。它的代码行更少,并且使用了一个专为构建字符串而设计的类。

The other consideration is which is more efficient. The best way to answer that would be to benchmark the two alternatives. But there are some clear pointers that StringBuilder shouldbe faster. For a start, a StringWriter uses a StringBuilderStringBuffer under the hood to hold the characters written to the "stream".

另一个考虑是哪个更有效。回答这个问题的最好方法是对这两种选择进行基准测试。但是有一些明确的指示表明 StringBuilder应该更快。首先,StringWriter 在底层使用StringBuilderStringBuffer 来保存写入“流”的字符。

回答by krock

Writers- PrintWriter writes to a stream. It does weird things like suppressing IOExceptions. System.out is one of these. - StringWriter is a Writer that writes to a StringBuffer (similar to ByteArrayOutputStream for OutputStreams)

Writers- PrintWriter 写入流。它会做一些奇怪的事情,比如抑制 IOExceptions。System.out 就是其中之一。- StringWriter 是一个写入 StringBuffer 的 Writer(类似于 OutputStreams 的 ByteArrayOutputStream)

StringBuilder- and of course StringBuilder is what you want if you are simply want to constructs strings in memory.

StringBuilder- 当然,如果您只是想在内存中构造字符串,那么 StringBuilder 就是您想要的。

Conclusion

结论

Writers by design are meant to push character data out a stream (usually to a file or through a connection) so being able to use Writers to simply assemble strings seems to be a bit of a side effect.

Writers 的设计意图是将字符数据推出一个流(通常是到一个文件或通过一个连接),所以能够使用 Writers 来简单地组合字符串似乎有点副作用。

StringBuilder (and its synchronized sibling StringBuffer) are designedto assemble strings (read string bashing). If you look at the StringBuilder APIyou can see thatnot only can you do vanilla appending but also replace, reverse, insert etc. StringBuilder is your String construction friend.

StringBuilder(及其同步的兄弟 StringBuffer)旨在组装字符串(读取字符串攻击)。如果您查看StringBuilder API,您会发现您不仅可以进行普通追加,还可以进行替换、反转、插入等操作。 StringBuilder 是您构建字符串的朋友。

回答by Alan Moore

StringWriter is what you use when when you want to write to a string, but you're working with an API that expects a Writer or a Stream. It's not an alternative, it's a compromise: you use StringWriter only when you have to.

当您想要写入字符串时使用 StringWriter,但您正在使用需要 Writer 或 Stream 的 API。这不是替代方案,而是一种折衷:只有在必须时才使用 StringWriter。

回答by CPerkins

Okay, since the answers seem to stress the stylistic reasons for preferring one over the other, I decided to gen up a timing test.

好的,由于答案似乎强调了偏爱一个而不是另一个的风格原因,我决定进行时间测试。

Edit: Following robinst's comment above, I now have three methods: one which does PrintWriter(StringWriter)-style appending, and two which use StringBuilder: one with the append of the newline inside the append (as in the original: builder.append(thing + newline);), and the other does a separate append (as above: builder.append(thing).append(newline);).

编辑:按照上面 robinst 的评论,我现在有三种方法:一种进行 PrintWriter(StringWriter) 样式的附加,另两种使用 StringBuilder:一种在附加内附加换行符(如原始:)builder.append(thing + newline);,以及other 做一个单独的追加(如上:)builder.append(thing).append(newline);

I followed my usual benchmarking scheme: call the methods several (1000 in this case) times first to give the optimizer time to warm up, then call each a large number of times (100,000 in this case) in alternating sequence, so that any changes in the workstation's runtime environment are more fairly distributed, and run the test itself several times and average the results.

我遵循了我通常的基准测试方案:首先调用这些方法几次(在这种情况下为 1000)次,以使优化器有时间预热,然后以交替顺序多次调用每个方法(在这种情况下为 100,000),以便任何更改在工作站的运行时环境中分布更公平,并多次运行测试本身并平均结果。

Oh, and of course the number of lines created and the length of the lines is randomized but held to be the same for each pair of calls, because I wanted to avoid any possible effects of buffer size or line size on the results.

哦,当然,创建的行数和行的长度是随机的,但对于每对调用保持相同,因为我想避免缓冲区大小或行大小对结果的任何可能影响。

The code for this is here: http://pastebin.com/vtZFzuds

代码在这里:http: //pastebin.com/vtZFzuds

Note: I have not yet updated the pastebin code to reflect the new test.

注意:我还没有更新 pastebin 代码来反映新的测试。

TL,DR?The average results for 100,000 calls to each method are quite close:

特尔,博士?每个方法 100,000 次调用的平均结果非常接近:

  • 0.11908 ms per call using StringBuilder (+newline inside the paren)
  • 0.10201 ms per call using StringBuilder (newline as a separate append)
  • 0.10803 ms per call using PrintWriter(StringWriter)
  • 使用 StringBuilder 每次调用 0.11908 毫秒(括号内的+换行符)
  • 使用 StringBuilder 每次调用 0.10201 毫秒(换行作为单独的追加)
  • 使用 PrintWriter(StringWriter) 每次调用 0.10803 毫秒

That's so close that the timing is nearly irrelevant to me, so I'm going to continue doing things the way I always did: StringBuilder(with separate append), for stylistic reasons. Of course, while working in this established and mature codebase, I'll mostly keep to the existing conventions, in order to minimize surprise.

如此接近以至于时间对我来说几乎无关紧要,因此出于风格原因,我将继续按照我一直做的方式做事:StringBuilder(带有单独的附加)。当然,在这个成熟的代码库中工作时,我将主要遵守现有的约定,以尽量减少意外。

回答by pjbarnes

I see two advantages of the PrintWriter method: (1) You don't have to add " + newline" at the end of every single line, which actually results in shorter code if you have a lot of writing to do. (2) You don't have to call System.getProperty(); you let the PrintWriter worry about what the newline character should be.

我看到了 PrintWriter 方法的两个优点:(1) 您不必在每一行的末尾添加“+换行符”,如果您有很多写作要做,这实际上会导致代码更短。(2) 你不必调用 System.getProperty(); 你让 PrintWriter 担心换行符应该是什么。

回答by omid haghighatgoo

in this link : http://nohack.eingenetzt.com/java/java-stringwriter-vs-stringbuilderthe author shows that the StringWriter is even slightly faster than the StringBuilder.and also said : "So when bigger amounts of data come into play the StringWriter clearly shows its superiority in performance over the StringBuilder."

在此链接中:http: //nohack.eingenetzt.com/java/java-stringwriter-vs-stringbuilder作者表明 StringWriter 甚至比 StringBuilder 略快,并且还说:“因此,当更多数据进入播放 StringWriter 清楚地表明它在性能上优于 StringBuilder。”