我正在使用 Scala 将文件写入磁盘。
为了创建将写入文件的整个字符串,我当前正在迭代数据并将所有信息附加到 StringBuilder 对象。
例如:
val moreData = getMoreData
strBuilder.append(moreData)
strBuilder.append("even more data")
//...
strBuilder.toString
在操作结束时,我调用 StringBuilder 的 toString 方法,并写入 Path。
我知道 Scala 对字符串有编译优化,所以我的问题是:
哪种方法性能更好。字符串插值连接还是 StringBuilder?
这些编译优化与 StringBuilder 有某种关系吗?换句话说,StringBuilder追加操作有优化吗?
字符串插值串联使用
StringBuilder
来生成其结果。可以进一步优化字符串插值,但就目前情况而言,它主要是为了表达能力而不是性能而设计的。如果您知道字符串创建会受到限制,则应该使用 StringBuilder
,并且这样做并不难。如果您不知道,或者您知道这不是一个主要问题,那么字符串插值通常更容易阅读,因此在大多数情况下您应该更喜欢它。
连接多个字符串的最有效方法是使用
StringBuilder
。
但是你的任务不是关于字符串连接。将多个字符串写入文件的最有效方法是使用旧的 java 的
FileWriter
和 BufferedWriter
:
val fw = new FileWriter("foo.out")
val bw = new BufferedWriter(fw)
strings.foreach {
s =>
bw.write(s)
}
bw.close()
fw.close()
如果您需要格式化功能,您可以选择用
BufferedWriter
包裹 PrintWriter
。
当然,如果您更看重性能而不是代码大小,那么以上所有内容都是正确的。
我在 VB.NET 中编写了以下测试程序,令我有点惊讶的是,字符串连接比插值字符串和字符串生成器都快。然而,显然,当进行更多附加操作时,字符串生成器将开始获胜,如最后三个测试所示。
Imports System.Text
Module Module1
Sub Main()
Dim sw As New Stopwatch
sw.Start()
For i As Integer = 0 To 1000000
Dim s As String = "DateModified=" & GetString("@auditdatemodified") & ",UserModifiedID = " & GetString("@audituseroptionsid")
If s = "" Then
Throw New Exception
End If
Next
sw.Stop()
Console.WriteLine("concat " & sw.ElapsedMilliseconds)
sw = New Stopwatch
sw.Start()
For i As Integer = 0 To 1000000
Dim s As String = $"DateModified={GetString("@auditdatemodified")},UserModifiedID = {GetString("@audituseroptionsid")}"
If s = "" Then
Throw New Exception
End If
Next
sw.Stop()
Console.WriteLine("interp " & sw.ElapsedMilliseconds)
sw = New Stopwatch
sw.Start()
For i As Integer = 0 To 1000000
Dim sb As New StringBuilder
sb.Append("DateModified=").Append(GetString("@auditdatemodified")).Append(",UserModifiedID = ").Append(GetString("@audituseroptionsid"))
Dim s As String = sb.ToString
If s = "" Then
Throw New Exception
End If
Next
sw.Stop()
Console.WriteLine("builder " & sw.ElapsedMilliseconds)
sw = New Stopwatch
sw.Start()
For i As Integer = 0 To 1000000
Dim s As String = "DateModified=" & GetString("@auditdatemodified") & ",UserModifiedID = " & GetString("@audituseroptionsid")
For j As Integer = 1 To 100
s = s & GetString("hello world")
Next
If s = "" Then
Throw New Exception
End If
Next
sw.Stop()
Console.WriteLine("concat many " & sw.ElapsedMilliseconds)
sw = New Stopwatch
sw.Start()
For i As Integer = 0 To 1000000
Dim s As String = $"DateModified={GetString("@auditdatemodified")},UserModifiedID = {GetString("@audituseroptionsid")}"
For j As Integer = 1 To 100
s = $"{s}{GetString("hello world")}"
Next
If s = "" Then
Throw New Exception
End If
Next
sw.Stop()
Console.WriteLine("interp many " & sw.ElapsedMilliseconds)
sw = New Stopwatch
sw.Start()
For i As Integer = 0 To 1000000
Dim sb As New StringBuilder
sb.Append("DateModified=").Append(GetString("@auditdatemodified")).Append(",UserModifiedID = ").Append(GetString("@audituseroptionsid"))
For j As Integer = 1 To 100
sb.Append(GetString("hello world"))
Next
Dim s As String = sb.ToString
If s = "" Then
Throw New Exception
End If
Next
sw.Stop()
Console.WriteLine("builder many " & sw.ElapsedMilliseconds)
Console.ReadLine()
End Sub
Private Function GetString(s) As String
Return s
End Function
End Module
我的电脑(最新的酷睿 i7 13 系列)上的结果:
concat 86
interp 150
builder 178
concat many 17607
interp many 45905
builder many 2827