string 使用 Groovy 进行字符串连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11359333/
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-09-09 01:32:05  来源:igfitidea点击:

String concatenation with Groovy

stringgroovyidiomsstring-concatenationgstring

提问by Arturo Herrero

What is the best (idiomatic) way to concatenate Strings in Groovy?

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

Option 1:

选项1:

calculateAccountNumber(bank, branch, checkDigit, account) {
    bank + branch + checkDigit + account
}

Option 2:

选项 2:

calculateAccountNumber(bank, branch, checkDigit, account) {
    "$bank$branch$checkDigit$account"
}

I've founded an interesting point about this topic in the old Groovy website: Things you can do but better leave undone.

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

As in Java, you can concatenate Strings with the "+" symbol. But Java only needs that one of the two items of a "+" expression to be a String, no matter if it's in the first place or in the last one. Java will use the toString() method in the non-String object of your "+" expression. But in Groovy, you just should be safe the first item of your "+" expression implements the plus() method in the right way, because Groovy will search and use it. In Groovy GDK, only the Number and String/StringBuffer/Character classes have the plus() method implemented to concatenate strings. To avoid surprises, always use GStrings.

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

回答by tim_yates

I always go for the second method (using the GString template), though when there are more than a couple of parameters like you have, I tend to wrap them in ${X}as I find it makes it more readable.

我总是采用第二种方法(使用 GString 模板),但是当像您这样有多个参数时,我倾向于将它们包装起来,${X}因为我发现它更具可读性。

Running some benchmarks (using Nagai Masato's excellent GBench module) on these methods also shows templating is faster than the other methods:

在这些方法上运行一些基准测试(使用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()

That gives me the following output on my machine:

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

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

So with readability and speed in it's favour, I'd recommend templating ;-)

因此,以可读性和速度为优势,我建议使用模板 ;-)

NB: If you add toString()to the end of the GString methods to make the output type the same as the other metrics, and make it a fairer test, StringBuilderand StringBufferbeat the GString methods for speed. However as GString can be used in place of String for most things (you just need to exercise caution with Map keys and SQL statements), it can mostly be left without this final conversion

注意:如果您添加toString()到 GString 方法的末尾以使输出类型与其他指标相同,并使其成为更公平的测试,StringBuilderStringBuffer在速度方面击败 GString 方法。然而,由于 GString 可以在大多数情况下代替 String 使用(您只需要小心使用 Map 键和 SQL 语句),因此大多数情况下它可以不进行最终转换

Adding these tests (as it has been asked in the comments)

添加这些测试(正如评论中所要求的那样)

  'GString template toString' {
    "$foo$bar$baz".toString()
  }
  'Readable GString template toString' {
    "${foo}${bar}${baz}".toString()
  }

Now we get the results:

现在我们得到结果:

String adder                        514
GString template                    267
Readable GString template           269
GString template toString           478
Readable GString template toString  480
StringBuilder                       321
StringBuffer                        369

So as you can see (as I said), it is slower than StringBuilder or StringBuffer, but still a bit faster than adding Strings...

所以正如你所看到的(正如我所说),它比 StringBuilder 或 StringBuffer 慢,但仍然比添加字符串快一点......

But still lots more readable.

但仍然更具可读性。

Edit after comment by ruralcoder below

在下面的乡村编码器评论后编辑

Updated to latest gbench, larger strings for concatenation and a test with a StringBuilder initialised to a good size:

更新到最新的 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()

gives

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

回答by Snowcrash

def my_string = "some string"
println "here: " + my_string 

Not quite sure why the answer above needs to go into benchmarks, string buffers, tests, etc.

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

回答by thoroc

Reproducing tim_yates answer on current hardware and adding leftShift() and concat() method to check the finding:

在当前硬件上重现 tim_yates 答案并添加 leftShift() 和 concat() 方法来检查发现:

  'String leftShift' {
    foo << bar << baz
  }
  'String concat' {
    foo.concat(bar)
       .concat(baz)
       .toString()
  }

The outcome shows concat() to be the faster solution for a pure String, but if you can handle GString somewhere else, GString template is still ahead, while honorable mention should go to leftShift() (bitwise operator) and StringBuffer() with initial allocation:

结果表明 concat() 是纯 String 的更快解决方案,但如果您可以在其他地方处理 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