プログラミングにおいて文字列の連結は頻繁に行われる基本的な処理のひとつですが、その記述方法にはいくつかの種類があります。それぞれの記述方法にはそれぞれの特性があり、利用目的に応じて適切に使い分けることでプログラムの品質が向上し信頼性の高いシステム開発につながります。
そこで、このコラムでは .NETのVisual BasicとC#を例にとり、文字列連結の記述方法とそれぞれの特性を解説していきます。
グレープシティ テクニカルエバンジェリスト
八巻 雄哉
2003年1月入社。PowerToolsシリーズのテクニカルサポートを担当するかたわら、製品開発やマーケティングにも従事。2006年から、.NETテクノロジーとPowerToolsシリーズ普及のためエバンジェリストとして活動中。
Microsoft MVP for Development Platforms -Client App Dev Jan 2009 -Dec 2010
+と&はどっちがよい?
Visual Basicでは、文字列連結に使える演算子として+演算子と&演算子の2つが存在します。文字列連結ということに限ればどちらの演算子も同じように使えますが、2つの演算子には決定的な違いがあります。それは、+演算子が数値加算と文字列連結の両方で使用できるのに対し、&演算子は文字列連結にしか使用できないという点です。
この違いは以下のようなコードで確認することができます。
Dim group As String = "1976"
Dim number As Integer = 48
Dim id1 As String = Group + Number
Dim id2 As String = Group & Number
Console.WriteLine("ID1={0}", id1)
Console.WriteLine("ID2={0}", id2)
Console.ReadKey()
実行結果 :
Id1=2024 Id2=197648
※Option StrictステートメントがOnの場合、上記の+演算子部分のコードはコンパイルエラーとなります。
一方が数値でもう一方が文字列の場合、+演算子を使うと文字列が数値型(Double)に変換され加算の処理が行われます。
MSDNライブラリの「+ 演算子 (Visual Basic)」には下記のような記載があります。
+ 演算子を使用すると、加算と文字列連結のどちらが行われるのか、事前にはわかりにくい場合があります。連結に & 演算子を使用することで、あいまいさがなくなり、プログラムの可読性が向上します。
これらのことから、Visual Basicで文字列連結を行う場合には、+演算子ではなく&演算子を使うべきと言えるでしょう。
String.Concatメソッド
+演算子や&演算子を使った文字列連結は、コンパイル時にString.Concatメソッドのいずれかのオーバーロードの呼び出しに置き換えられます。そのため、記述文字数が多くなるString.Concatメソッドをあえて使用する必要はあまりないでしょう。
文字列連結のパフォーマンス
.NETのStringデータ型は、インスタンス作成時以外に値を変更できない不変型です。文字列連結を含む値の変更は、実際には値が変更されているのではなく都度新しいインスタンスが生成されています。そのため、+演算子や&演算子を使って文字列連結を繰り返した場合、そのメモリ割り当てのコストから期待するパフォーマンスを得られないことがあります。
そのような場合に有効とされているのがStringBuilderクラスです。StringBuilderクラスは必要に応じてバッファサイズを拡大させて値の変更ができる可変型となっており、Appendメソッドを使って文字列の連結を行うことでメモリ領域の確保を最小限に抑えることができます。
このことはマイクロソフト社のサイトに限らず様々なサイトで取り上げられているため、ご存知の方も多いのではないかと思います。
どんなときにStringBuilderを使ったらよいの?
しかしながら、どんな場合でも+演算子や&演算子に比べてStringBuilderがパフォーマンス上有利というわけではありません。
+演算子や&演算子を使った場合でも、下記のように文字列定数を1ステートメントで連結させていればコンパイル時に文字列定数がひとまとめにされるため実行時に連結処理は発生しません。
Dim sql = "SELECT Column1, Column2, Column3" _
& " FROM Table1" _
& " WHERE Column1 = @Column1"
つまり、下記のコードと等価になります。
Dim sql = "SELECT Column1, Column2, Column3 FROM Table1 WHERE Column1 = @Column1"
また、定数ではなく変数であっても1ステートメント内の連結であれば、3つの場合にはString.Concat (String, String, String)、4つの場合にはString.Concat (String, String, String, String)、5つ以上の場合にはString.Concat (String[])の呼び出しに置き換えられるようになっているため、StringBuilder.Appendメソッドと比較してもパフォーマンス上大きく劣ることはありません。
プログラミングにおいてパフォーマンスを意識することは大切なことですが、コードの可読性や記述のしやすさもまた重要な要素であることに異論はないでしょう。単純に考えても、1文字の+演算子や&演算子に対してStringBuilder.Appendメソッドは“sb.Append()”と書いても11文字記述する必要があります。
個人的な見解となりますが、ループ処理を使って動的な文字列連結を繰り返す場合にはStringBuilderクラスを、それ以外の場合には+演算子や&演算子を使うとよいのではないでしょうか。
開発者はどう使い分けている?
2010年7月22日に配信したPowerNews 308号で今回のコラムで解説した「+演算子」「&算子」「String.Concatメソッド」「StirngBuilder.Appendメソッド」を開発者の皆さんが、どのように使っているのかアンケートを行いました。以下に回答結果と皆さまからいただいたコメントを紹介します。
質問内容
普段、文字列を連結する際にどのようなコードを書きますか?
- & 演算子
- + 演算子
- String.Concatメソッド
- StringBuilder.Appendメソッド
回答結果
アンケート実施日:2010/7/22
| 普段、文字列を連結する際にどのようなコードを書きますか? | 比率 |
|---|---|
| & 演算子 | 48% |
| + 演算子 | 16% |
| & 演算子, + 演算子 | 4% |
| & 演算子, StringBuilder.Appendメソッド | 4% |
| + 演算子, StringBuilder.Appendメソッド | 10% |
| & 演算子, + 演算子, StringBuilder.Appendメソッド | 4% |
| StringBuilder.Appendメソッド | 10% |
| String.Concatメソッド | 2% |
| String.Concatメソッド, StringBuilder.Appendメソッド | 2% |
| 総計 | 100% |
皆さんからいただいたコメント
他の方式を知る必要も無かったので、+演算子以外ははじめて知りました。
また+演算子は文字列結合でなく数値の加算になってしまいそうだから怖い。
単純に&の20倍の工数がかかります。この差は大きいです。
(しかし時間計測していないので、案外+演算子でも十分かも知れない)
どれが一番良いのでしょうか?
短い連結はString.Concatまたは、String.Formatを使ってます。