在 Groovy 中连接字符串的最佳(惯用)方法是什么?
选项1:
calculateAccountNumber(bank, branch, checkDigit, account) {
bank + branch + checkDigit + account
}
选项 2:
calculateAccountNumber(bank, branch, checkDigit, account) {
"$bank$branch$checkDigit$account"
}
我在旧的 Groovy 网站上就这个话题提出了一个有趣的观点:你可以做的事情,但最好不要做。
与在 Java 中一样,您可以使用“+”符号连接字符串。但是Java只需要“+”表达式的两项中的一项是字符串,无论它是在第一个还是在最后一个。 Java 将在“+”表达式的非字符串对象中使用 toString() 方法。但是在 Groovy 中,您应该确保“+”表达式的第一项以正确的方式实现 plus() 方法,因为 Groovy 会搜索并使用它。在 Groovy GDK 中,只有 Number 和 String/StringBuffer/Character 类实现了 plus() 方法来连接字符串。为避免意外,请始终使用 GStrings。
我总是选择第二种方法(使用 GString 模板),尽管当有多个像您这样的参数时,我倾向于将它们包装在 ${X}
中,因为我发现它更具可读性。
在这些方法上运行一些基准测试(使用 Nagai Masato 的优秀 GBench module)也表明模板比其他方法更快:
@Grab( 'com.googlecode.gbench:gbench:0.3.0-groovy-2.0' )
import gbench.*
def (foo,bar,baz) = [ 'foo', 'bar', 'baz' ]
new BenchmarkBuilder().run( measureCpuTime:false ) {
// Just add the strings
'String adder' {
foo + bar + baz
}
// Templating
'GString template' {
"$foo$bar$baz"
}
// I find this more readable
'Readable GString template' {
"${foo}${bar}${baz}"
}
// StringBuilder
'StringBuilder' {
new StringBuilder().append( foo )
.append( bar )
.append( baz )
.toString()
}
'StringBuffer' {
new StringBuffer().append( foo )
.append( bar )
.append( baz )
.toString()
}
}.prettyPrint()
这给了我机器上的以下输出:
Environment
===========
* Groovy: 2.0.0
* JVM: Java HotSpot(TM) 64-Bit Server VM (20.6-b01-415, Apple Inc.)
* JRE: 1.6.0_31
* Total Memory: 81.0625 MB
* Maximum Memory: 123.9375 MB
* OS: Mac OS X (10.6.8, x86_64)
Options
=======
* Warm Up: Auto
* CPU Time Measurement: Off
String adder 539
GString template 245
Readable GString template 244
StringBuilder 318
StringBuffer 370
因此,由于它具有可读性和速度,我建议使用模板 ;-)
注意:如果您将 toString()
添加到 GString 方法的末尾以使输出类型与其他指标相同,并使其成为更公平的测试,则 StringBuilder
和 StringBuffer
在速度方面优于 GString 方法。但是,由于 GString 可以在大多数情况下代替 String (您只需要小心使用 Map 键和 SQL 语句),因此大多数情况下都可以不进行最终转换
添加这些测试(正如评论中所要求的那样)
'GString template toString' {
"$foo$bar$baz".toString()
}
'Readable GString template toString' {
"${foo}${bar}${baz}".toString()
}
现在我们得到结果:
String adder 514
GString template 267
Readable GString template 269
GString template toString 478
Readable GString template toString 480
StringBuilder 321
StringBuffer 369
所以你可以看到(正如我所说),它比 StringBuilder 或 StringBuffer 慢,但仍然比添加字符串快一点......
但仍然更具可读性。
在下面的农村编码员评论后编辑
更新到最新的 gbench,用于连接的更大字符串以及使用 StringBuilder 初始化为合适大小的测试:
@Grab( 'org.gperfutils:gbench:0.4.2-groovy-2.1' )
def (foo,bar,baz) = [ 'foo' * 50, 'bar' * 50, 'baz' * 50 ]
benchmark {
// Just add the strings
'String adder' {
foo + bar + baz
}
// Templating
'GString template' {
"$foo$bar$baz"
}
// I find this more readable
'Readable GString template' {
"${foo}${bar}${baz}"
}
'GString template toString' {
"$foo$bar$baz".toString()
}
'Readable GString template toString' {
"${foo}${bar}${baz}".toString()
}
// StringBuilder
'StringBuilder' {
new StringBuilder().append( foo )
.append( bar )
.append( baz )
.toString()
}
'StringBuffer' {
new StringBuffer().append( foo )
.append( bar )
.append( baz )
.toString()
}
'StringBuffer with Allocation' {
new StringBuffer( 512 ).append( foo )
.append( bar )
.append( baz )
.toString()
}
}.prettyPrint()
给
Environment
===========
* Groovy: 2.1.6
* JVM: Java HotSpot(TM) 64-Bit Server VM (23.21-b01, Oracle Corporation)
* JRE: 1.7.0_21
* Total Memory: 467.375 MB
* Maximum Memory: 1077.375 MB
* OS: Mac OS X (10.8.4, x86_64)
Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On
user system cpu real
String adder 630 0 630 647
GString template 29 0 29 31
Readable GString template 32 0 32 33
GString template toString 429 0 429 443
Readable GString template toString 428 1 429 441
StringBuilder 383 1 384 396
StringBuffer 395 1 396 409
StringBuffer with Allocation 277 0 277 286
def my_string = "some string"
println "here: " + my_string
不太清楚为什么上面的答案需要进入基准测试、字符串缓冲区、测试等。
在当前硬件上重现 tim_yates 答案并添加 leftShift() 和 concat() 方法来检查结果:
'String leftShift' {
foo << bar << baz
}
'String concat' {
foo.concat(bar)
.concat(baz)
.toString()
}
结果显示 concat() 是纯字符串的更快解决方案,但如果您可以在其他地方处理 GString,则 GString 模板仍然领先,而值得一提的是 leftShift()(按位运算符)和 StringBuffer() 初始分配:
Environment
===========
* Groovy: 2.4.8
* JVM: OpenJDK 64-Bit Server VM (25.191-b12, Oracle Corporation)
* JRE: 1.8.0_191
* Total Memory: 238 MB
* Maximum Memory: 3504 MB
* OS: Linux (4.19.13-300.fc29.x86_64, amd64)
Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On
user system cpu real
String adder 453 7 460 469
String leftShift 287 2 289 295
String concat 169 1 170 173
GString template 24 0 24 24
Readable GString template 32 0 32 32
GString template toString 400 0 400 406
Readable GString template toString 412 0 412 419
StringBuilder 325 3 328 334
StringBuffer 390 1 391 398
StringBuffer with Allocation 259 1 260 265
不定期副业成功案例分享
.toString()
附加到两个 GString 测试。我的运行表明它们的性能几乎与String adder
相同。我的猜测是您运行的测试实际上并没有处理连接,所以它只是创建一个 GString 对象并存储引用。如果您在某些时候需要String
,StringBuilder
仍然是最快的。GString
保留为“原样”,在 some 点它也必须转换为真正的String
,(即使只是为了打印出来),所以真正的时机是最后一组。最后,当时间如此接近时,GString
模板的易读性胜过StringBuilder
,因此没有实际意义。 :-)