Groovy ile dize birleştirme


91

Groovy'de Dizeleri birleştirmenin en iyi (deyimsel) yolu nedir?

Seçenek 1:

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

Seçenek 2:

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

Eski Groovy web sitesinde bu konuyla ilgili ilginç bir noktaya değindim: Yapabileceğiniz şeyler ama yapmadan bıraksanız iyi olur.

Java'da olduğu gibi, Dizeleri "+" sembolüyle birleştirebilirsiniz. Ancak Java, bir "+" ifadesinin iki öğesinden birinin, ister ilk sırada ister sonuncu olsun, yalnızca Dize olmasına ihtiyaç duyar. Java, "+" ifadenizin String olmayan nesnesinde toString () yöntemini kullanır. Ancak Groovy'de güvende olmalısınız, "+" ifadenizin ilk öğesi plus () yöntemini doğru şekilde uygular, çünkü Groovy onu arayacak ve kullanacaktır. Groovy GDK'da, yalnızca Number ve String / StringBuffer / Character sınıfları, dizeleri birleştirmek için uygulanan plus () yöntemine sahiptir. Sürprizlerden kaçınmak için her zaman GStrings kullanın.

Yanıtlar:


122

Her zaman ikinci yöntemi tercih ederim (GString şablonunu kullanarak), yine de sizin gibi birkaç parametreden daha fazlası olduğunda, onları ${X}daha okunaklı hale getirdiği için bunları sarmalama eğilimindeyim .

Bu yöntemlerde bazı kıyaslamaları çalıştırmak ( Nagai Masato'nun mükemmel GBench modülünü kullanarak ), şablonlamanın diğer yöntemlerden daha hızlı olduğunu da gösterir:

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

Bu bana makinemde şu çıktıyı veriyor:

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

Okunabilirlik ve hız lehine, şablonlamayı tavsiye ederim ;-)

Not: Eğer eklerseniz toString()çıkış diğer ölçümlere aynı tip yapmak gstring yöntemlerin sonuna kadar ve daha adil bir testi yapmak, StringBuilderve StringBufferhız için gstring yöntemleri yendi. Bununla birlikte, GString çoğu şey için String yerine kullanılabileceğinden (sadece Harita anahtarları ve SQL ifadeleri ile dikkatli olmanız gerekir), çoğunlukla bu son dönüştürme olmadan bırakılabilir.

Bu testleri eklemek (yorumlarda sorulduğu gibi)

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

Şimdi sonuçları alıyoruz:

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

Gördüğünüz gibi (dediğim gibi), StringBuilder veya StringBuffer'dan daha yavaştır, ancak yine de Strings eklemekten biraz daha hızlıdır ...

Ama yine de çok daha okunabilir.

Aşağıdaki kırsal kodlayıcı tarafından yapılan yorumdan sonra düzenleyin

En son gbench, birleştirme için daha büyük dizeler ve iyi bir boyuta başlatılmış bir StringBuilder ile bir test ile güncellendi:

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

verir

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

3
Okunabilirlik için GString şablonlarının kullanımına katılmıyorum, ancak testleri .toString()iki GString testine eklenmiş olarak yeniden çalıştırmalısınız . Koşum, daha sonra neredeyse aynı performans gösterdiklerini gösteriyor String adder. Tahminimce, çalıştırdığınız test aslında birleştirme işlemini ele almıyor, bu yüzden sadece bir GString nesnesi oluşturup referansları depoluyor. StringBuilderhala en hızlısı, bir Stringnoktada ihtiyacınız varsa, eller aşağı .
hevesli

1
Bunun ikinci yarısını bir şekilde kaçırdım! Tabii ki, GString"olduğu gibi" bıraksanız bile , bir noktada doğruya dönüştürülmesi gerekir String(sadece yazdırmak için bile), bu nedenle gerçek zamanlama son settir. Sonunda, zamanlama bu kadar yakın olduğunda GStringşablonların okunabilirliği daha StringBuilderiyidir, bu yüzden tartışmalıdır. :-)
OverZealous

2
@OverZealous Ahhh evet, her zaman olduğu gibi, yalanlar, lanet olası yalanlar ve kıyaslamalar var ;-) Okunabilirliğin burada anahtar olduğunu hissediyorum ve Groovy'yi zaten kullandığımız için, çıplak metal performansın bizim ana düşüncemiz olmadığını belirttik; -)
tim_yates

1
Evet, GStrings'in en büyük avantajlarından biri, son ana kadar dizelere dönüştürülmemeleri. Bu, örneğin, günlük kaydı eşiğinin altında log4j gibi bir kaydediciye sahip bir GString'i günlüğe kaydederseniz, GString'in hiçbir zaman dönüştürülmediği anlamına gelir.
ataylor

1
Testte eksik olan, hesaplanan kapasiteye sahip StringBuilder'dır. Bunun nedeni, foo + bar + baz'ın zamana ek olarak bir veya iki tampon genişlemesine neden olmasıdır.
countrycoder

19
def my_string = "some string"
println "here: " + my_string 

Yukarıdaki cevabın neden kıyaslamalara, dizgi tamponlarına, testlere vb. Girmesi gerektiğinden tam olarak emin değilim.


2
Basitlik için oy verin. Sadece iki dizgeyi birleştirmem gerekiyor. lol
harperville

2

Mevcut donanımda tim_yates yanıtını yeniden oluşturmak ve bulguyu kontrol etmek için leftShift () ve concat () yöntemini eklemek:

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

Sonuç, concat () 'nin saf bir String için daha hızlı çözüm olduğunu gösteriyor, ancak GString'i başka bir yerde idare edebiliyorsanız, GString şablonu hala ilerideyken, şeref sözü leftShift () (bitwise operatörü) ve StringBuffer ()' a gitmelidir. tahsis:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.