web-dev-qa-db-fra.com

Concaténation de cordes avec Groovy

Quel est le meilleur moyen (idiomatique) de concaténer Strings dans Groovy?

Option 1:

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

Option 2:

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

J'ai trouvé un point intéressant sur ce sujet dans l'ancien site Web de Groovy: Ce que vous pouvez faire, mais il vaut mieux laisser non réalisé.

Comme en Java, vous pouvez concaténer des chaînes avec le symbole "+". Mais Java Il suffit que l'un des deux éléments d'une expression "+" soit un String, peu importe si c'est en premier ou en dernier lieu. Java utilisera la méthode toString () dans l’objet non-String de votre "+" expression. Mais dans Groovy, vous devriez juste être en sécurité le premier élément de votre expression "+" implémente la méthode plus () de la bonne manière, parce que Groovy va chercher et l'utiliser. Dans Groovy GDK, seul le nombre et les classes String/StringBuffer/Character utilisent la méthode plus () mis en œuvre pour concaténer des chaînes. Pour éviter les surprises, utilisez toujours GStrings.

72
Arturo Herrero

J'utilise toujours la deuxième méthode (en utilisant le modèle GString), bien que, quand il y a plus que deux paramètres comme vous, j'ai tendance à les envelopper dans ${X} car je le trouve plus lisible.

L'exécution de tests (en utilisant l'excellent module GBench de Nagai Masato ) sur ces méthodes montre également que la modélisation est plus rapide que les autres méthodes:

@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()

Cela me donne la sortie suivante sur ma 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

Donc, avec la lisibilité et la rapidité en sa faveur, je recommanderais de créer des templates ;-)

NB: Si vous ajoutez toString() à la fin des méthodes GString pour que le type de sortie soit identique aux autres métriques et que vous en fassiez un test plus juste, StringBuilder et StringBuffer dépassent les méthodes GString pour la vitesse. Cependant, comme GString peut être utilisé à la place de String pour la plupart des choses (vous devez simplement faire preuve de prudence avec les clés de la carte et les instructions SQL), il peut généralement être laissé sans cette conversion finale.

Ajout de ces tests (comme cela a été demandé dans les commentaires)

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

Maintenant nous obtenons les résultats:

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

Donc, comme vous pouvez le constater (comme je l'ai dit), il est plus lent que StringBuilder ou StringBuffer, mais reste un peu plus rapide que d'ajouter des chaînes ...

Mais toujours beaucoup plus lisible.

Éditer après le commentaire par ruralcoder ci-dessous

Mise à jour vers gbench, des chaînes plus grandes pour la concaténation et un test avec StringBuilder initialisé à une taille correcte:

@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()

donne

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
109
tim_yates
def my_string = "some string"
println "here: " + my_string 

Vous ne savez pas très bien pourquoi la réponse ci-dessus doit entrer dans les tests de performance, les mémoires tampons, les tests, etc.

2
Snowcrash

Reproduire la réponse de tim_yates sur le matériel actuel et ajouter les méthodes leftShift () et concat () pour vérifier le résultat:

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

Le résultat montre que concat () est la solution la plus rapide pour un String pur, mais si vous pouvez gérer GString ailleurs, le modèle GString est toujours en avance, alors que la mention honorable devrait aller à leftShift () (opérateur au niveau du bit) et StringBuffer allocation:

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
0
thoroc