String concatenation with Groovy

匿名 (未验证) 提交于 2019-12-03 02:44:02

问题:

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

Option 1:

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

Option 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.

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.

回答1:

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.

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

@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, StringBuilder and StringBuffer beat 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

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...

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:

@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


转载请标明出处:String concatenation with Groovy
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!