Java で文字列を扱う際、多くの開発者が最初に触れるのは String クラスです。しかし、String は不変(immutable)であるという特性を持つため、文字列の連結や変更を繰り返す処理ではパフォーマンスに大きな影響を与えます。
そのような場面で利用されるのが StringBuilder と StringBuffer です。
本記事では、StringBuilder と StringBuffer の違いを正確に整理し、内部構造やスレッド安全性、性能面の違い、実際の利用シーンに応じた使い分けまでを丁寧に解説します。
String クラスの制約と可変文字列クラスの必要性
String クラスは一度生成すると内容を変更できません。
以下のようなコードでは、一見文字列を追加しているように見えますが、内部的には新しい String オブジェクトが生成されています。
|
1 2 |
String s = "Hello"; s = s + " World"; |
このような処理をループ内で何度も実行すると、不要なオブジェクト生成が繰り返され、メモリ使用量と処理時間の両面で非効率になります。
この問題を解決するために、Java には可変(mutable)な文字列クラスとして StringBuilder と StringBuffer が用意されています。
StringBuilder の特徴
StringBuilder は、文字列の変更を前提として設計されたクラスです。
内部では可変長の文字配列を保持しており、append や insert といった操作によって同一オブジェクト内で文字列を変更します。
|
1 2 3 4 |
StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("World"); |
主な特徴
・スレッドセーフではない
・同期処理を行わないため高速
・単一スレッド環境での利用に適している
StringBuilder は Java 5 以降で導入され、パフォーマンス重視の用途を想定しています。
StringBuffer の特徴
StringBuffer は StringBuilder とほぼ同じ API を持ちますが、大きな違いはスレッド安全性です。
|
1 2 3 4 |
StringBuffer sb = new StringBuffer(); sb.append("Hello"); sb.append(" "); sb.append("World"); |
主な特徴
・スレッドセーフ
・すべての主要メソッドが synchronized で同期されている
・複数スレッドから同時に操作される可能性がある場合に安全
StringBuffer は Java 初期から存在するクラスで、マルチスレッド環境での安全性を重視しています。
内部構造の違い
StringBuilder と StringBuffer は、どちらも内部に文字配列(char[])を持ち、容量が不足すると自動的に拡張されます。
拡張時のアルゴリズムも基本的には共通です。
違いは同期制御の有無のみです。
・StringBuilder:同期なし
・StringBuffer:メソッド単位で同期あり
この同期処理が、性能差の主な原因になります。
パフォーマンスの違い
単一スレッド環境では、StringBuilder の方が StringBuffer より高速です。
理由は明確で、StringBuffer は不要な同期処御を毎回行うためです。
一般的な業務アプリケーションやバッチ処理、Web アプリケーションのリクエスト単位の処理では、同一インスタンスを複数スレッドで共有するケースは多くありません。
そのため、実務では StringBuilder が選択される場面が圧倒的に多いのが実情です。
マルチスレッド環境での考え方
「マルチスレッド環境だから StringBuffer を使うべき」という理解は正確ではありません。
重要なのは、同一のインスタンスを複数スレッドから同時に操作するかどうかです。
・各スレッドごとに StringBuilder を生成する → 問題なし
・1 つの StringBuilder を複数スレッドで共有 → 非推奨
・どうしても共有する必要がある → StringBuffer もしくは外部で同期制御
多くのケースでは、インスタンスを共有しない設計にすることで StringBuilder を安全に使用できます。
StringBuilder と StringBuffer の使い分け指針
以下の基準で判断すると明確です。
・単一スレッド、またはスレッドごとにインスタンスを分けられる
→ StringBuilder
・複数スレッドから同一インスタンスを安全に操作する必要がある
→ StringBuffer
特別な理由がない限り、新規開発では StringBuilder を選択するのが一般的です。
StringBuilder と StringBuffer の主なメソッド比較
両クラスは API がほぼ共通です。
・append
・insert
・delete
・reverse
・length
・toString
コードの書き方はほぼ同じで、クラス名を差し替えるだけで動作します。
reverse メソッドの利用例
文字列を反転させる処理は、StringBuilder / StringBuffer の代表的な利用例です。
|
1 2 |
String text = "ABCDE"; String reversed = new StringBuilder(text).reverse().toString(); |
このように簡潔かつ効率的に処理できます。
よくある質問(Q & A)
- StringBuilder と StringBuffer はどちらを使うべきですか?
-
原則として StringBuilder を使用してください。同一インスタンスを複数スレッドで共有する必要がある場合のみ StringBuffer を検討します。
- Web アプリケーションでは StringBuffer が安全ですか?
-
Web アプリケーションでも、リクエスト単位でインスタンスを生成する場合は StringBuilder で問題ありません。
- StringBuffer を使うと必ず遅くなりますか?
-
同期処理が入るため、単一スレッドでは StringBuilder より遅くなります。ただし処理内容によって差が小さい場合もあります。
- String と StringBuilder を混在させても問題ありませんか?
-
問題ありません。最終的に toString で String に変換する使い方が一般的です。
まとめ
StringBuilder と StringBuffer の違いは、スレッド安全性とそれに伴う性能差に集約されます。
現在の Java 開発においては、ほとんどの場面で StringBuilder が最適な選択となります。
重要なのは「マルチスレッドかどうか」ではなく「インスタンスを共有するかどうか」です。
この点を正しく理解することで、無駄な性能低下や設計ミスを防ぐことができます。
