3.

Java StringBufferの使い方|append・insertとStringBuilderの違い

編集
この記事の要点
  • StringBuffer は Java の可変な文字列を扱うクラス(java.lang.StringBuffer
  • String不変(immutable)+= のたびに新オブジェクトが作られメモリ効率が悪い
  • append / insert / delete / reverse 等で同一オブジェクトを書き換えられる
  • StringBuilder(同 API でスレッド非対応)とStringBuffer(スレッドセーフ)がある。通常は StringBuilder 推奨
  • String に戻すには toString()new String(sb) も可だがあまり使わない

StringBuffer とは

StringBuffer は Java で可変の文字列を表すクラスです。String 型が不変(immutable)であるのに対し、StringBuffer同じオブジェクトを書き換えられるため、文字列の連結や編集を大量に行う場合にメモリと CPU の両方で効率的です。

String との違い

項目StringStringBuffer
可変性不変(immutable)可変(mutable)
連結方法+ 演算子append() メソッド
連結のコスト毎回新オブジェクト生成同オブジェクトを更新
大量連結時の性能遅い(O(N²))速い(O(N))
スレッドセーフ○(不変だから)○(同期化されている)

基本的な使い方

StringBuffer sb = new StringBuffer("val1");
sb.append(" val2");        // 末尾に追加
sb.append(" val3");
System.out.println(sb);    // val1 val2 val3

// String に変換
String result = sb.toString();

主要メソッド

メソッド用途
append(x)末尾に追加(あらゆる型を受ける)
insert(i, x)位置 i に挿入
delete(start, end)範囲削除
deleteCharAt(i)1 文字削除
replace(start, end, str)範囲置換
reverse()逆順
length()長さ
charAt(i)i 番目の文字
substring(s, e)部分文字列
toString()String に変換

使用例

StringBuffer sb = new StringBuffer();

// append: あらゆる型を受け取れる
sb.append("ID=");
sb.append(123);          // int
sb.append(", flag=");
sb.append(true);         // boolean
sb.append(", pi=");
sb.append(3.14);         // double
System.out.println(sb);  // ID=123, flag=true, pi=3.14

// insert: 0 文字目に "Hello " を挿入
sb.insert(0, "Hello ");

// delete: 5 〜 8 文字目を削除
sb.delete(5, 8);

// replace: 範囲を置換
sb.replace(0, 5, "Hi");

// reverse: 逆順
StringBuffer r = new StringBuffer("abcdef");
r.reverse();             // fedcba
System.out.println(r);

String との連結性能比較

1 万回ループで文字列を連結すると、性能差が劇的に表れます。

// NG: String の + 連結(毎回新オブジェクト)
String s = "";
for (int i = 0; i < 10000; i++) {
    s += i;   // 内部で StringBuilder が作られて消える
}
// ループ全体で O(N²)、Big-O では 10000² = 1 億回の文字コピー

// OK: StringBuffer で連結
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10000; i++) {
    sb.append(i);
}
// O(N)、ループ全体で 1 万回。100倍以上速い

StringBuffer vs StringBuilder

Java 5 で導入された StringBuilder は、StringBufferほぼ同じ APIを持つ可変文字列クラスですが、スレッドセーフではない代わりに高速です。

項目StringBufferStringBuilder
導入Java 1.0Java 5
スレッドセーフ○(synchronized)×
速度遅い(同期化のオーバーヘッド)速い
推奨度マルチスレッド共有時のみ★ 通常はこちら

結論: シングルスレッドや1 メソッド内のローカル変数として使うなら StringBuilder複数スレッドで共有するなら StringBuffer。実務では StringBuilder を使う場面が圧倒的に多いです。

String への変換

StringBuffer sb = new StringBuffer("hello");

// 推奨: toString()
String s1 = sb.toString();

// 可: new String(sb)
String s2 = new String(sb);

// 部分文字列
String s3 = sb.substring(0, 3);  // "hel"

容量と性能

StringBuffer は内部にバッファ(char 配列)を持ち、容量が足りなくなると拡張します。あらかじめサイズが分かっている場合、初期容量を指定すると拡張コストを削減できます。

// デフォルトの初期容量は 16 文字
StringBuffer sb1 = new StringBuffer();

// 容量を指定
StringBuffer sb2 = new StringBuffer(1024);

// 文字列リテラルで初期化(length + 16)
StringBuffer sb3 = new StringBuffer("hello");

// 容量の確認
System.out.println(sb3.capacity());  // 21
System.out.println(sb3.length());    // 5

// 容量の確保
sb3.ensureCapacity(100);

メソッドチェーン

append / insert 等は自分自身を返すので、メソッドチェーンで書けます。

String result = new StringBuffer()
    .append("Hello, ")
    .append("World")
    .append('!')
    .append(2026)
    .toString();
// "Hello, World!2026"

String.format と比較

固定フォーマットの文字列を組み立てるなら String.formatprintf 形式の方が読みやすいことがあります。

// StringBuffer
String s1 = new StringBuffer()
    .append("User=").append(name)
    .append(", age=").append(age)
    .toString();

// String.format
String s2 = String.format("User=%s, age=%d", name, age);

// テキストブロック(Java 15+)+ formatted
String s3 = """
    User=%s, age=%d
    """.formatted(name, age);

FAQ

Q: + 連結は常に遅い?
A: 単発の連結("A" + "B")は問題なし。コンパイラが StringBuilder に変換するため1 行内の連結は最適化されています。問題なのはループ内+=

Q: StringBuffer は古い?
A: 古いコードでは見かけますが、新規コードでマルチスレッド共有が不要なら StringBuilder を使うのが現代の作法です。

関連

  • String — 不変な文字列クラス
  • StringBuilder — スレッド非対応の高速版
  • String.format — printf スタイルのフォーマット
  • String.join — リストの結合
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. String.equals
  2. String.equalsIgnoreCase(大文字小文字を無視した等値比較)
  3. StringBuffer
  4. String.length
  5. String.trim

最近更新/作成されたページ