it-swarm.com.de

String-Verkettung mit Groovy

Was ist der beste (idiomatische) Weg, um Strings in Groovy zu verketten?

Option 1:

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

Option 2:

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

Ich habe in der alten Groovy-Website einen interessanten Punkt zu diesem Thema gefunden: Dinge, die Sie tun können, aber besser ungeschehen lassen.

Wie in Java können Sie Strings mit dem Symbol "+" verketten. Aber Java Benötigt nur eines der beiden Elemente eines "+" - Ausdrucks als String, egal ob es sich um den ersten oder den letzten handelt. Java verwendet die toString () -Methode im Nicht-String-Objekt Ihres "+" Ausdruck. In Groovy sollten Sie jedoch das erste Element von .__ sicher sein. Ihr "+" - Ausdruck implementiert die plus () - Methode auf die richtige Art und Weise weil Groovy suchen und benutzen wird. In Groovy GDK wird nur die Nummer und String/StringBuffer/Character-Klassen haben die plus () -Methode implementiert, um Strings zu verketten. Um Überraschungen zu vermeiden, verwenden Sie immer GStrings.

72
Arturo Herrero

Ich gehe immer für die zweite Methode (mit der GString-Vorlage). Wenn es jedoch mehr als ein paar Parameter wie Sie gibt, neige ich dazu, sie in ${X} einzuwickeln, da ich sie für lesbarer halte.

Das Durchführen einiger Benchmarks (mit Nagai Masato s ausgezeichnetem GBench-Modul ) für diese Methoden zeigt auch, dass das Templating schneller ist als die anderen Methoden:

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

Das gibt mir folgende Ausgabe auf meiner Maschine:

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

Da Lesbarkeit und Schnelligkeit im Vorteil sind, empfehle ich die Vorlage ;-)

Hinweis: Wenn Sie am Ende der GString-Methoden toString() hinzufügen, damit der Ausgabetyp den anderen Metriken entspricht, und einen faireren Test durchführen, schlagen StringBuilder und StringBuffer die GString-Methoden für die Geschwindigkeit. Da GString jedoch für die meisten Dinge anstelle von String verwendet werden kann (Sie müssen nur mit Map-Schlüsseln und SQL-Anweisungen Vorsicht walten lassen), kann es meistens ohne diese abschließende Konvertierung bleiben

Hinzufügen dieser Tests (wie in den Kommentaren verlangt)

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

Jetzt bekommen wir die Ergebnisse:

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

Wie Sie (wie gesagt) sehen können, ist es langsamer als StringBuilder oder StringBuffer, aber immer noch etwas schneller als das Hinzufügen von Strings ...

Aber noch viel lesbarer.

Bearbeiten Sie nach Kommentar von ruralcoder unten

Auf den neuesten Stand gbench aktualisiert, größere Strings für die Verkettung und ein Test mit einem StringBuilder, der auf eine gute Größe initialisiert wurde:

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

gibt

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 

Nicht ganz sicher, warum die Antwort oben auf Benchmarks, Stringpuffer, Tests usw. eingehen muss.

2
Snowcrash

Antwort von tim_yates auf der aktuellen Hardware und Hinzufügen der Methode leftShift () und concat () zur Überprüfung der Ergebnisse:

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

Das Ergebnis zeigt, dass concat () die schnellere Lösung für einen reinen String ist. Wenn Sie GString jedoch auch an anderer Stelle verwenden können, ist die GString-Vorlage noch vor Ihnen Zuweisung:

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