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