Java StringBuilderクラス
Javaにおける StringBuilder クラスは、文字列の変更を効率的に処理するために設計されています。作成後に値を変更できないイミュータブル(不変)な String クラスとは異なり、StringBuilder は新しいオブジェクトを都度生成することなく、文字シーケンスを直接変更できます。
これは大量の文字列操作を行う際に非常に有効で、メモリオーバーヘッドを劇的に削減し、パフォーマンスを向上させることができます。StringBuilder はミュータブル(可変)な文字シーケンスを提供し、文字の追加(追加)、挿入、削除、置換のためのメソッドを備えています。StringBuilder をマスターすることは、効率的な Java コードを書くための鍵となります。
1. StringBuilder クラスを理解する
StringBuilder クラスは java.lang パッケージに属しているため、明示的なインポートなしでプログラム内で直接使用できます。本質的には、変更可能な文字のシーケンスを表します。
1.1 String の不変性 vs StringBuilder の可変性
これが両者の最も核心的な違いです:
- String:オブジェクトはイミュータブルです。String を変更(連結や置換など)するたびに、完全に新しい String オブジェクトが作成されます。
String str = "Hello";
str = str + " World"; // 新しい String オブジェクトが作成される
str = str.replace("World", "Java"); // さらに新しい String オブジェクトが作成される
System.out.println(str); // 出力: Hello Java上の例では、実際には "Hello"、"Hello World"、"Hello Java" という3つのオブジェクトがメモリ上に作成されています。
- StringBuilder:オブジェクトはミュータブルです。変更は基底の文字シーケンスに直接作用し、余分なオブジェクトを生成しません。
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // オリジナルの StringBuilder オブジェクトを直接変更
sb.replace(6, 11, "Java"); // 同じオブジェクトをそのまま変更
System.out.println(sb); // 出力: Hello Javaこの方式は、ループ内での連結や頻繁な修正が発生するシーンで極めて高い効率を発揮します。
2. StringBuilder オブジェクトの作成
StringBuilder は以下のようないくつかの方法でインスタンス化できます:
1. 空のオブジェクト: デフォルトのキャパシティ(通常は 16 文字)を持つインスタンスを作成します。
StringBuilder sb1 = new StringBuilder();
System.out.println(sb1.capacity()); // 出力: 162. 初期キャパシティの指定: 文字列が長くなることがあらかじめわかっている場合、サイズを指定して自動拡張(リサイズ)のオーバーヘッドを減らすことができます。
StringBuilder sb2 = new StringBuilder(50);3. 初期内容の指定: 既存の文字列に基づいて作成します。キャパシティは通常、文字列の長さ + 16 に設定されます。
StringBuilder sb3 = new StringBuilder("Initial Text");3. StringBuilder の主要メソッド
StringBuilder はテキスト操作のための豊富なメソッドを提供しています:
- append(): 末尾に文字列や他のデータ型を追加します。
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World").append(123); // メソッドチェーンをサポート- insert(): 指定したインデックス位置に内容を挿入します。
sb.insert(5, ", Java"); // 実行結果: "Hello, Java World"- replace(): 指定した範囲内の文字シーケンスを置換します。
sb.replace(6, 11, "Java");- delete() および deleteCharAt(): 範囲指定または特定のインデックスの文字を削除します。
sb.delete(5, 11); // インデックス 5 から 11 の内容を削除
sb.deleteCharAt(4); // インデックス 4 の文字を削除- reverse(): 文字シーケンス全体を反転させます。
sb.reverse(); // 例: "Hello" -> "olleH"- length() と capacity():
length()は実際の文字数を返します。capacity()は現在割り当てられているストレージ空間のサイズを返します。
4. StringBuilder vs StringBuffer
Java には StringBuffer という非常によく似たクラスも存在します。機能はほぼ同一ですが、主な違いは以下の点です:
- StringBuffer: スレッドセーフ(同期化)。マルチスレッド環境に適していますが、同期化のオーバーヘッドがあるため、シングルスレッドでは速度が低下します。
- StringBuilder: スレッドセーフではありません。シングルスレッド環境でのパフォーマンスがより優れており、ほとんどの一般的なシナリオではこちらが推奨されます。
5. 実践ケーススタディ
5.1 カンマ区切りのリストを構築する
String[] items = {"Apple", "Banana", "Orange"};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < items.length; i++) {
sb.append(items[i]);
if (i < items.length - 1) {
sb.append(", ");
}
}
System.out.println(sb.toString()); // 出力: Apple, Banana, Orange5.2 HTML テーブルの行を生成する
String[] rowData = {"Tanaka", "30", "Tokyo"};
StringBuilder tableRow = new StringBuilder();
tableRow.append("<tr>");
for (String data : rowData) {
tableRow.append("<td>").append(data).append("</td>");
}
tableRow.append("</tr>");6. ベストプラクティス
- ループ内では StringBuilder を使用する:
forやwhileループの中で String の+演算子による連結は絶対に避けてください。大量のテンポラリオブジェクトが生成され、GC(ガベージコレクション)の負荷が高まります。 - キャパシティのプリセット: 最終的な文字列が約 1000 文字になるとわかっている場合、初期化時に
new StringBuilder(1000)と指定することで、内部配列の再割り当てを回避できます。 - メソッドチェーンの活用: 各メソッドが自分自身のインスタンスを返す特性を活かし、コードを簡潔に記述しましょう:
sb.append("a").append("b").reverse();