在Scala中,字符串连接是否像Java一样代价高昂?

46
在Java中,由于使用+运算符添加字符串的性能较差,使用StringBuilder进行字符串拼接是一种常见的最佳实践。是否推荐在Scala中采用相同的做法,或者这种语言在如何执行字符串连接方面已经有所改进?
4个回答

49

Scala使用Java字符串(java.lang.String),因此它的字符串连接与Java相同:两者都执行相同的操作。(毕竟运行时是相同的。) Scala中有一个特殊的StringBuilder类,它"提供了与java.lang.StringBuilder兼容的API";请参见http://www.scala-lang.org/api/2.7.5/scala/StringBuilder.html

但就"最佳实践"而言,我认为大多数人通常会认为编写简单、清晰的代码比编写最大限度有效的代码更好,除非存在实际性能问题或有好的理由可以预期性能问题。 +运算符并没有真正的"性能差",只是s += "foo" 等同于 s = s + "foo"(即它创建一个新的String 对象),这意味着,如果你要对(看起来像)"单个字符串"进行许多连接操作,则可以通过使用StringBuilder而不是String来避免创建不必要的对象——并且重复从一个字符串复制早期部分到另一个字符串。通常情况下,这种差异并不重要。(当然,"简单、清晰的代码"略有矛盾:使用+=更简单,使用StringBuilder更清晰。但是,决策通常应基于编写代码的考虑,而不是次要的性能考虑。)


1
在我的情况下,我非常关注性能,因此我才会提出这个问题。感谢您提供的所有信息! - bionicseraph
据我所知,JVM会自动将表达式中重复的“+”连接方式与StringBuffer相同对待。因此实际上没有性能差异。 - aishwarya
@aishwaryaпјҡJLSе»әи®®зј–иҜ‘еҷЁе°Ҷfoo + bar + baz + bipдјҳеҢ–дёәзӯүж•Ҳзҡ„new StringBuilder(foo).append(bar).append(baz).append(bip).toString()пјҢ并е°Ҷ"foo" + "bar" + "baz" + "bip"дјҳеҢ–дёә"foobarbazbip"пјҢдҪҶиҝҷдәӣжғ…еҶөзӣёеҪ“зӢӯзӘ„гҖӮжҲ‘и®ӨдёәJVMпјҲдёҺзј–иҜ‘еҷЁзӣёеҸҚпјүйҖҡеёёдёҚдјҡиҝӣиЎҢд»»дҪ•зұ»дјјзҡ„дјҳеҢ–пјҢе°Ҫз®ЎжҲ‘еҸҜиғҪжҳҜй”ҷзҡ„гҖӮ - ruakh
12
个人烦恼:在循环中使用 "+" 运算符会导致 O(n^2) 的复杂度,而使用 StringBuilder 可以做到 O(n)。虽然额外的对象是一个小问题,但复杂度的激增是一个重大问题。 - Philip Potter
@PhilipPotter:说得好。我已经编辑了我的答案,提到 StringBuilder 也有助于避免“重复从一个字符串复制早期部分到另一个字符串”的问题。 - ruakh

21

Scala的字符串拼接与Java相同。

val x = 5
"a"+"b"+x+"c"

被翻译成

new StringBuilder()).append("ab").append(BoxesRunTime.boxToInteger(x)).append("c").toString()

StringBuilder 是 scala.collection.mutable.StringBuilder。这就是为什么附加到 StringBuilder 的值被编译器装箱的原因。

您可以通过使用 javap 反编译字节码来检查此行为。


6

我想补充一点:如果你有一系列字符串,那么已经有一种方法可以将它们创建成一个新的字符串(所有项都被连接)。它被称为mkString

例如:(http://ideone.com/QJhkAG)

val example = Seq("11111", "2222", "333", "444444")
val result = example.mkString
println(result) // prints "111112222333444444"

2

Scala使用java.lang.String作为字符串类型,因此它具有相同的特点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接