Javaで文字列を結合する全手法まとめ|+演算子・StringBuilder・joinの違いと使い分け

目次

1. はじめに

Javaで文字列を結合したい――プログラミング初心者から現場の開発者まで、必ず一度は直面するテーマです。たとえば「複数の名前をまとめて1つの文章にしたい」「データベースへのSQL文を組み立てたい」「ログにわかりやすいメッセージを出力したい」など、文字列結合は多くの用途で欠かせません。

しかし、「どの方法が一番いいの?」「+演算子とStringBuilderって何が違うの?」といった疑問や、「大量のデータを結合したら急に処理が遅くなった」などのトラブルを経験する方も多いのではないでしょうか。

本記事では、Javaで文字列を結合するすべての主な方法について、初心者にも分かりやすく徹底解説します。単純な連結方法から、パフォーマンス・メモリ効率・最新バージョンでの推奨パターンまで、幅広くカバー。さらに、現場で役立つベストプラクティスや、「結局どれを選べばいい?」という実務的な選択基準まで明確にまとめました。

これからJavaでの文字列結合をマスターしたい方や、今のやり方が最適なのか再確認したい方は、ぜひ最後までご覧ください。あなたの開発現場で、すぐに役立つ知識がきっと見つかります。

2. Javaにおける文字列結合の基礎

Javaプログラミングにおいて「文字列の結合」は非常に頻繁に登場する操作ですが、その仕組みを正しく理解している人は意外と多くありません。まずは、Javaの文字列の基本と、結合時に知っておくべきポイントを押さえておきましょう。

2.1 文字列はイミュータブル(不変)なオブジェクト

JavaのString型はイミュータブル(不変)という性質を持っています。これは、一度生成された文字列は、その内容を後から変更できないということです。
例えば、次のようなコードを書いた場合、

String a = "Hello";
a = a + " World!";

変数aには”Hello World!”が格納されますが、内部的には「新しい文字列オブジェクト」が作成され、もともとの”Hello”の内容は変更されていません。
この仕組みは安全性やバグ防止に役立つ反面、大量の結合処理を行うとメモリ効率や処理速度に影響が出ることがあります。

2.2 文字列結合が多いと遅くなる?その理由

プログラム中で何度も+演算子を使って文字列を繰り返し結合すると、そのたびに新しい文字列オブジェクトが生成され、古い文字列は使われなくなります。
例えば、次のようなループ処理を考えてみましょう。

String result = "";
for (int i = 0; i < 1000; i++) {
    result = result + i;
}

この場合、1000回のループごとに毎回新しい文字列が作られるため、メモリ消費と処理速度がどんどん悪化してしまいます。
この現象は「文字列結合の落とし穴」として、特にパフォーマンス重視の開発現場では注意が必要です。

2.3 まずは基本の結合方法を理解しよう

Javaで文字列を結合する代表的な方法は主に2つです。
1つは、+演算子(例:a + b)。もう1つは、concat()メソッド(例:a.concat(b))です。
どちらも簡単に使えますが、使い方や内部動作の違いを理解しておくことが、後で効率的なプログラムを書くための第一歩になります。

3. 結合手法の比較と選び方【表・図解付き】

Javaで文字列を結合する方法はひとつではありません。代表的な手法は、「+演算子」「concat()メソッド」「StringBuilder/StringBuffer」「String.join()やStringJoiner」「String.format()」など、バージョンや用途によって様々です。それぞれの特徴や向いている場面、注意点を解説し、効率的な使い分け方を示します。

3.1 + 演算子による結合

もっとも直感的で簡単な方法が、+演算子を使った結合です。次のように複数の文字列や値をつなぐことができます。

String firstName = "Taro";
String lastName = "Yamada";
String fullName = firstName + " " + lastName;

Javaでは、+演算子で2つ以上の文字列を結合した場合、裏側でStringBuilderが使われるように最適化されています(Java8以降)。しかし、ループなどで何度も連結する場合は、パフォーマンス面で注意が必要です。

3.2 String.concat()メソッド

concat()メソッドも基本的な結合方法のひとつです。

String a = "Hello, ";
String b = "World!";
String result = a.concat(b);

この方法もシンプルですが、nullを渡すと例外が発生するため、実務では使われることが少ないのが現状です。

3.3 StringBuilderStringBufferによる結合

パフォーマンスを意識するなら、StringBuilder(もしくはスレッド安全性が必要な場合はStringBuffer)を利用します。
特にループで複数回の結合が発生する場合は必須と言ってよいでしょう。

StringBuilder sb = new StringBuilder();
sb.append("Java");
sb.append("文字列");
sb.append("結合");
String result = sb.toString();

3.4 String.join()StringJoiner(Java8以降)

複数の要素を区切り文字付きで結合したい場合、Java8以降ならString.join()StringJoinerが便利です。

List<String> words = Arrays.asList("Java", "文字列", "結合");
String joined = String.join(",", words);

3.5 String.format()やその他の方法

フォーマット済みの文字列を作成したい場合は、String.format()が活躍します。

String name = "Sato";
int age = 25;
String result = String.format("名前:%s、年齢:%d", name, age);

3.6 比較表(用途と特徴)

方法速度可読性ループ向きバージョンコメント
+演算子△〜○×全バージョンシンプルだがループでは非推奨
concat()×全バージョンnullに注意
StringBuilder全バージョンループ・大量処理で最速
StringBuffer全バージョンマルチスレッド時に推奨
String.join()Java8以降配列・リスト結合で便利
String.format()×全バージョン複雑な整形・可読性重視に最適

3.7 図解:手法選びのイメージ

  • 短い一時的な結合:+演算子
  • ループや大量データ:StringBuilder
  • コレクションや配列:String.join()
  • マルチスレッド:StringBuffer
  • フォーマット整形:String.format()

4. ユースケース別ベストプラクティス

Javaで文字列を結合する方法は多様ですが、「どの場面で、どの手法を使えばよいのか?」という具体的な判断基準を知っておくことが、現場の効率化とトラブル防止に直結します。この章では、よくある実務シーンごとに最適な結合方法とその理由を解説します。

4.1 短い一時的な結合には「+」演算子

コードの中で一度だけ文字列を繋ぐ場合や、数回程度の結合ならば、+演算子で十分です。

String city = "Osaka";
String weather = "晴れ";
String message = city + "の天気は" + weather + "です。";
System.out.println(message);

4.2 ループや大量の結合には「StringBuilder」

繰り返し処理や、数十回以上の結合が発生する場合は、必ずStringBuilderを使いましょう。

StringBuilder sb = new StringBuilder();
for (String word : words) {
    sb.append(word);
}
String output = sb.toString();
System.out.println(output);

4.3 コレクション・配列まとめて結合には「String.join()」や「StringJoiner」

配列やリスト、コレクション内の全要素を区切り文字付きで結合したい場合は、String.join()StringJoinerが便利です。

List<String> fruits = Arrays.asList("りんご", "バナナ", "ぶどう");
String csv = String.join(",", fruits);
System.out.println(csv);

4.4 マルチスレッド環境では「StringBuffer」

並列処理やスレッドセーフな環境では、StringBuilderではなくStringBufferを使うことで、安全に文字列を結合できます。

StringBuffer sb = new StringBuffer();
sb.append("Safe");
sb.append(" and ");
sb.append("Sound");
System.out.println(sb.toString());

4.5 null混在や特殊パターンには工夫が必要

要素にnullが含まれる可能性がある場合、String.join()では例外が発生します。安全に結合したい場合は、あらかじめnull除去や変換処理を挟むのがベストです。

List<String> data = Arrays.asList("A", null, "C");
String safeJoin = data.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.joining(","));
System.out.println(safeJoin);

4.6 フォーマット指定や複雑な整形には「String.format」

複数の変数を見やすい形で結合・整形したいときは、String.format()が役立ちます。

String name = "Tanaka";
int age = 32;
String message = String.format("名前:%s 年齢:%d", name, age);
System.out.println(message);

まとめ

  • 一時的な少数結合→「+」演算子
  • ループや大量結合→「StringBuilder」
  • コレクションの区切り付き結合→「String.join()」や「StringJoiner」
  • 並列・スレッドセーフ必要→「StringBuffer」
  • null・特殊パターンや整形→事前処理や「String.format」など工夫

5. 【実践】主要パターンのコード例集

ここでは、Javaでよく使われる文字列結合パターンについて、具体的なコード例を用途別に紹介します。実務や学習でそのまま使える形でまとめているので、ぜひコピペやアレンジにご活用ください。

5.1 「+」演算子による単純な結合

String city = "Osaka";
String weather = "晴れ";
String message = city + "の天気は" + weather + "です。";
System.out.println(message);

5.2 concat()メソッドの利用

String a = "Java";
String b = "言語";
String result = a.concat(b);
System.out.println(result);

5.3 StringBuilderでのループ結合

StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
    sb.append("No.").append(i).append(" ");
}
String output = sb.toString();
System.out.println(output);

5.4 StringBufferのスレッド安全な結合

StringBuffer sb = new StringBuffer();
sb.append("Safe");
sb.append(" and ");
sb.append("Sound");
System.out.println(sb.toString());

5.5 String.join()で配列やリストを結合

List<String> fruits = Arrays.asList("りんご", "バナナ", "ぶどう");
String csv = String.join(",", fruits);
System.out.println(csv);

5.6 StringJoinerで柔軟な結合

StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("A").add("B").add("C");
System.out.println(joiner.toString());

5.7 Stream APIとCollectors.joining()の応用

List<String> data = Arrays.asList("one", null, "three");
String result = data.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.joining("/"));
System.out.println(result);

5.8 String.format()での整形・結合

String user = "佐藤";
int age = 29;
String info = String.format("名前:%s、年齢:%d", user, age);
System.out.println(info);

5.9 配列を文字列化する(Arrays.toStringの例)

int[] scores = {70, 80, 90};
System.out.println(Arrays.toString(scores));

まとめ

用途や状況に合わせて最適な手法を選ぶことで、Java開発の効率や品質が大きく向上します。

6. バージョンごとの違いと最新トレンド

Javaは長い歴史の中で進化を続けてきました。文字列結合に関しても、Javaのバージョンアップによって「推奨される書き方」や「内部動作の最適化」に大きな違いがあります。この章では、Javaのバージョンごとの主な違いと、現代的な開発で意識すべき最新トレンドを解説します。

6.1 Java 7までの文字列結合の常識

  • +演算子による結合は「シンプルだが、ループでは非効率」というのが通説でした。
  • 複数回の結合やループ内での連結は、必ずStringBuilderを使うべきとされてきました。
  • Java7以前は、+演算子による結合がそのまま連続して実行され、新しいStringインスタンスが大量に生成されるため、特にループでパフォーマンス劣化が顕著でした。

6.2 Java 8以降の最適化

  • Java8以降、+演算子を使った結合はコンパイル時や実行時に内部的にStringBuilderへと自動変換されるようになり、単純な結合であれば、以前ほど深刻な性能低下が起きにくくなりました。
  • それでも、ループでの+演算子連結は依然として「ベストプラクティス」ではなく、多回数の結合ではStringBuilderString.join()が推奨です。
  • Java8からはString.join()StringJoinerが追加され、コレクションの一括結合が格段に便利になりました。

6.3 Java 11/17以降の変化や新機能

  • Java 11やJava 17といったLTS(長期サポート)バージョンでも、文字列結合API自体は大きく変わりませんが、JVMのパフォーマンス最適化が進み、+演算子もより効率よく動作します。
  • また、String.repeat()や、より強力なStream APIも追加され、文字列の生成や結合パターンの幅が広がっています。

6.4 「昔の常識」が通用しない時代へ

  • Javaの進化により、「昔は絶対NG」だった手法が今では許容されるケースも増えています。
  • 例えば、数回の+演算子での結合や、単純なif文の中での+利用は、現代のJVMではほとんど問題になりません。
  • ただし、大量結合やループの中での+演算子は今もパフォーマンス面でリスクが残るため、現場では依然としてStringBuilder推奨が基本です。

6.5 最新トレンド:可読性とパフォーマンスのバランス

  • コードの読みやすさ、保守性を優先する場面では、過度な最適化よりも「シンプルな記述」や「標準的なAPIの活用」が評価されています。
  • たとえば、「可読性重視なら+演算子」「パフォーマンス重視や複雑な結合処理はStringBuilderjoin()」という使い分けが主流です。
  • また、最新の開発現場では「Stream APIとCollectors.joining()」を使った宣言的な記述も人気です。

まとめ

Javaの文字列結合は、バージョンによって最適解が変わることもあります。「昔の常識」やネット上の古い記事にとらわれず、現代のJavaに合ったベストプラクティスを選ぶことが大切です。

7. よくある質問(FAQ)

Javaで文字列を結合する際、実務でも学習でも多くの人がつまずきやすいポイントや、よくある疑問がいくつかあります。この章では、そんな悩みにピンポイントでお答えします。

Q1. ループ内で「+」演算子を使うと、なぜ遅くなるのですか?

+演算子はシンプルで直感的ですが、ループの中で使うと毎回新しい文字列インスタンスが生成されてしまいます。たとえば、1000回ループして+で連結した場合、合計で1000回分の新しい文字列オブジェクトがメモリ上に作られ、GC(ガーベジコレクション)の負荷や速度低下の原因になります。ループ処理にはStringBuilderを使うのが定石です。

Q2. StringBuilderとStringBufferの違いは何ですか?

どちらも可変長の文字列バッファですが、StringBuilderはスレッド非安全、StringBufferはスレッド安全という違いがあります。通常の単一スレッド処理ならStringBuilderが高速でおすすめ。マルチスレッド環境で同時に文字列を結合・編集する必要がある場合は、StringBufferを選びましょう。

Q3. String.join()はnullを含むリストで使えますか?

String.join()は、リスト内にnullが含まれているとNullPointerExceptionが発生します。安全に使いたい場合は、あらかじめnullを除去するか、Stream APIfilter(Objects::nonNull)を利用して結合しましょう。

Q4. String.format()は結合に使ってもパフォーマンスに問題ありませんか?

String.format()は可読性やフォーマットの柔軟性に優れていますが、単純な結合で多用するとやや処理速度が落ちる傾向があります。パフォーマンス最優先の場面では、StringBuilderString.join()を活用するのが良いでしょう。

Q5. 英語圏の情報やStack Overflowの回答は参考になりますか?

はい、特にベンチマーク比較やJDKの内部実装に関する話題は英語圏の記事やStack Overflowの回答が最新かつ実践的です。ただし、「昔の情報」やバージョン依存のテクニックには注意し、常に自分のJavaバージョンに合わせて確認することが大切です。

Q6. 結合対象がnullの場合、エラーを避ける方法は?

concat()String.join()は、nullを結合しようとするとエラーになります。+演算子の場合は、nullを文字列”null”として扱います。実務では、事前にObjects.toString(値, "")Optional.ofNullable(値).orElse("")でnullガードするのが安全です。

Q7. パフォーマンスを最大化したい時のチェックポイントは?

  • ループや大量結合はStringBuilder一択
  • 配列やコレクションはString.join()Collectors.joining()
  • 必要以上の最適化よりも、まずは「シンプルで間違えない」書き方を優先し、問題が出たらベンチマークで最適化
  • JVMやJDKのバージョンアップ情報にも目を向ける

8. まとめ・おすすめフローチャート

本記事では、Javaにおける文字列結合の基本から応用、パフォーマンスやバージョンごとの違いまで、幅広く解説してきました。ここで、記事全体の要点をまとめ、実務や学習で迷わないための選択ガイドを紹介します。

8.1 要点まとめ

  • 「+」演算子
    一時的な少量結合や可読性を重視したいときに最適。ループや大量処理には不向き。
  • StringBuilder
    繰り返しや大量の結合、高速化が必要な場面で必須。現場のデファクトスタンダード。
  • StringBuffer
    マルチスレッド環境で安全性が必要な場合に限定して利用。
  • String.join()/StringJoiner
    配列・リスト・コレクションの一括結合や区切り文字付き結合に便利。Java8以降のモダンな選択肢。
  • String.format()
    フォーマット済みの出力や、見やすさ重視の整形に適している。
  • Stream API/Collectors.joining()
    null除外や条件付き結合など、高度なパターンや柔軟な実装に有効。

8.2 用途別・手法選択フローチャート

実務やコーディング中に迷ったら、次のフローチャートを参考にしましょう。

1. ループで大量に結合する → StringBuilder
2. 配列やリストをまとめて結合 → String.join()/Collectors.joining()
3. スレッド安全が必須 → StringBuffer
4. 一時的で数回の結合 → +
5. フォーマットや整形が必要 → String.format()
6. null要素や条件付き → Stream API+filter+Collectors.joining()
7. それ以外/特殊パターン → 要件に応じて柔軟に選択

8.3 実務で迷ったときのポイント

  • 「どれでも動く」なら、まずは読みやすさ重視で。
  • パフォーマンスや安全性が気になる場面だけ、ベンチマークや公式ドキュメントを参照。
  • 不安なときは最新版のJDKドキュメントや信頼できる情報を確認する。

8.4 今後のバージョンアップ情報の収集方法

  • Oracle公式ドキュメントやJava Magazine
  • Stack OverflowやQiitaの最新記事
  • JEP(Java Enhancement Proposal)の一覧ページ

まとめ

Javaの文字列結合は、用途やバージョン、プロジェクトの規模によって最適解が変わります。「どの方法も正解」ですが、状況に合わせた選択ができることがエンジニアとしての実力です。本記事の知識を活かして、より効率的でトラブルのないコーディングを目指しましょう。

9. 参考文献・外部リンク集

より深い理解や実装の裏付け、最新動向のチェックには、信頼性の高いドキュメントや有名技術サイトの活用が不可欠です。ここでは、Javaの文字列結合に関する学習・実務で役立つ参考文献や外部リンクをまとめます。

9.1 公式ドキュメント・技術解説

9.2 技術記事・実践ノウハウ

9.3 学びを深めるためのおすすめ

9.4 注意点とアドバイス

  • 記事やブログは日付やバージョン情報を必ずチェックし、自分の開発環境に合った内容か確認しましょう。
  • 公式ドキュメントやコミュニティの議論も積極的に参照し、「昔の常識」と「今の推奨」を見極める姿勢が大切です。