Конкатенация строк с помощью Groovy

Каков наилучший (идиоматический) способ конкатенации строк в Groovy?

Вариант 1:

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

Вариант 2:

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

Я основал интересный момент в этой теме на старом веб-сайте Groovy: все, что вы можете сделать, но лучше оставить без изменений.

Как и в Java, вы можете конкатенировать строки с символом "+". Но Java требуется только, чтобы один из двух элементов выражения "+" был Строка, независимо от того, будет она в первую очередь или в последней. Ява будет использовать метод toString() в объекте non-String вашего "+", выражение. Но в Groovy вы просто должны быть в безопасности первым элементом ваше выражение "+" реализует метод plus() в правильном направлении, потому что Groovy будет искать и использовать его. В Groovy GDK только номер и классы String/StringBuffer/Character имеют метод plus() реализованы для объединения строк. Чтобы избежать сюрпризов, всегда используйте GStrings.

Ответ 1

Я всегда использую второй метод (используя шаблон 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()

Это дает мне следующий результат на моей машине:

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 для большинства вещей (вам просто нужно проявлять осторожность при использовании ключей карты и операторов 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

Ответ 2

Воспроизведение ответа 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