[解決済み] 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 は、"+" 式の2つの項目のうち1つが文字列であることだけが必要です。 しかし、Javaでは、"+"式の2つの項目のうち1つが文字列であればよく、それが最初であろうと最後であろうと、文字列は必要ありません。Java は、"+".式の非StringオブジェクトでtoString()メソッドを使用します。 の式に変換します。しかし、Groovyでは、最初の項目が安全であればよいのです。 しかし、Groovyの場合は、"+"式の最初の項目が正しい方法でplus()メソッドを実装していることを確認するだけです。 というのも、Groovyではそれを検索して使うからです。Groovy GDKでは、Number(数値) とString/StringBuffer/Characterクラスだけが、文字列を連結するためのplus() メソッドを実装しています。 メソッドが実装されています。驚かないように、常に GStringsを使用してください。
どのように解決するのですか?
私はいつも2番目の方法(GStringテンプレートを使用する)をとりますが、あなたのようにパラメータが2つ以上ある場合は、それらを
${X}
で囲むことが多いのですが、その方が読みやすくなります。
いくつかのベンチマークを実行し ( 永井正人 の優れた 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の代わりにほとんどのことに使用できるので(Mapキーと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よりは遅いですが、それでもStringを追加するよりは少し速いです...。
しかし、まだずっと読みやすい。
ruralcoderさんのコメントを受けて編集しました。
最新の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
関連
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] なぜパスワードにはStringではなくchar[]が好まれるのですか?
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] バイトを文字列に変換する
-
[解決済み] Bashで文字列変数を連結する方法
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】大文字・小文字を区別しない「Contains(string)
-
[解決済み] 文字の後に文字列を取得する[重複]。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] デリミタによる文字列の分割
-
[解決済み】文字列から最後の文字を削除する。Swift言語
-
[解決済み】複数行の文字列リテラルの構文とは何ですか?
-
[解決済み] T-SQLのPadLeft関数
-
[解決済み] groovyのシングルクォート、ダブルクォート内の文字列の違いは何ですか?
-
[解決済み] 文字列の先頭文字の取得と削除
-
[解決済み] 文字列を変数名に変換する
-
[解決済み] Int を、先頭のゼロを揃えて、指定された長さの文字列に変換するにはどうしたらいいですか?
-
[解決済み] ScalaでInputStreamを文字列に変換する方法
-
[解決済み] 文字列の最後の4文字を取得する方法は?重複