使用Groovy进行字符串连接

Art*_*ero 84 string groovy idioms string-concatenation gstring

在Groovy中连接字符串的最佳(惯用)方法是什么?

选项1:

calculateAccountNumber(bank, branch, checkDigit, account) {
    bank + branch + checkDigit + account
}
Run Code Online (Sandbox Code Playgroud)

选项2:

calculateAccountNumber(bank, branch, checkDigit, account) {
    "$bank$branch$checkDigit$account"
}
Run Code Online (Sandbox Code Playgroud)

我在旧的Groovy网站上找到了一个关于这个主题的有趣观点:你可以做的事情,但最好不要做.

与在Java中一样,您可以使用"+"符号连接字符串.但是Java只需要将"+"表达式的两个项中的一个作为String,无论它是在第一个位置还是在最后一个.Java将在"+"表达式的非String对象中使用toString()方法.但是在Groovy中,你应该是安全的,你的"+"表达式的第一项以正确的方式实现了plus()方法,因为Groovy将搜索并使用它.在Groovy GDK中,只有Number和String/StringBuffer/Character类实现了连接字符串的plus()方法.为避免意外,请始终使用GStrings.

tim*_*tes 115

我总是选择第二种方法(使用GString模板),虽然当你有多个参数时,我倾向于将它们包装起来,${X}因为我发现它使它更具可读性.

在这些方法上运行一些基准测试(使用Nagai Masato优秀的GBench模块)也表明模板比其他方法更快:

@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()
Run Code Online (Sandbox Code Playgroud)

这给了我在我的机器上的以下输出:

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
Run Code Online (Sandbox Code Playgroud)

因此,有了它的可读性和速度,我建议模板;-)

注意:如果添加toString()到GString方法的末尾以使输出类型与其他度量相同,并使其成为更公平的测试,StringBuilder并且StringBuffer为了速度而击败GString方法.但是,因为大多数事情都可以使用GString来代替String(你只需要谨慎使用Map键和SQL语句),它可以在没有这个最终转换的情况下离开

添加这些测试(正如评论中提到的那样)

  'GString template toString' {
    "$foo$bar$baz".toString()
  }
  'Readable GString template toString' {
    "${foo}${bar}${baz}".toString()
  }
Run Code Online (Sandbox Code Playgroud)

现在我们得到结果:

String adder                        514
GString template                    267
Readable GString template           269
GString template toString           478
Readable GString template toString  480
StringBuilder                       321
StringBuffer                        369
Run Code Online (Sandbox Code Playgroud)

正如你所看到的(正如我所说),它比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()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 我不同意使用GString模板的易读性,但你应该重新运行测试,并在两个GString测试中附加`.toString()`.我的运行显示它们的表现几乎与`String adder`相同.我的猜测是你运行的测试实际上并没有处理连接,所以它只是创建一个GString对象并存储引用.如果你在某个时候需要一个`String`,那么`StringBuilder`仍然是最快的. (3认同)
  • @OverZealous啊,是的,一如既往,有[谎言,该死的谎言和基准](http://en.wikipedia.org/wiki/Lies,_damned_lies,_and_statistics);-)可读性是关键,我觉得和我们一样我已经在使用Groovy了,我们已经说裸机性能不是我们主要的考虑因素;-) (2认同)

Sno*_*ash 9

def my_string = "some string"
println "here: " + my_string 
Run Code Online (Sandbox Code Playgroud)

不太确定为什么以上答案需要进入基准测试,字符串缓冲区,测试等。

  • 为简单点赞。我只需要连接两个字符串。哈哈 (8认同)