join処理は「バラバラの要素を“1本の文字列”にまとめる」技
業務システムでは、
「IDをカンマ区切りでログに出したい」
「SQLの IN ('A','B','C') を組み立てたい」
「画面に 山田 / 佐藤 / 鈴木 のように表示したい」
こういう「複数要素を、区切り文字付きの1本の文字列にしたい」場面が本当に多いです。
この「要素をつなげて1本にする」処理が、ここでいう join 処理です。
Java には String.join や Collectors.joining など、join 専用の仕組みが用意されています。
これをうまくユーティリティ化しておくと、業務コードがかなりスッキリします。
一番基本:String.join で List をつなげる
文字列の List を区切り文字で join する
まずは、List<String> をカンマ区切りにする基本形です。
import java.util.List;
public class JoinBasic {
public static void main(String[] args) {
List<String> names = List.of("山田", "佐藤", "鈴木");
String joined = String.join(",", names);
System.out.println(joined); // 山田,佐藤,鈴木
}
}
Javaここでの重要ポイントは二つです。
一つ目は、「String.join(区切り文字, Iterable<String>) という形で、“区切り文字”と“文字列の集まり”を渡すだけでよい」ことです。
自分で StringBuilder を回したり、最後の区切りを消したりする必要はありません。
二つ目は、「要素が0件なら空文字列、1件ならそのまま、2件以上なら区切り文字付きでつながる」という挙動が、すべて String.join に任せられることです。
“最後に余計なカンマが付く”といったありがちなバグを、最初から避けられます。
Stream と Collectors.joining の組み合わせ
変換しながら join したいとき
「そのままの文字列をつなげる」のではなく、
「何かに変換してから join したい」こともよくあります。
例えば、「数値の List をカンマ区切り文字列にしたい」場合。
import java.util.List;
import java.util.stream.Collectors;
public class JoinWithStream {
public static void main(String[] args) {
List<Integer> scores = List.of(80, 90, 75);
String joined =
scores.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
System.out.println(joined); // 80,90,75
}
}
Javaここでの重要ポイントは三つです。
一つ目は、「Collectors.joining(区切り文字) が、“Stream<String> を1本の文字列にまとめる Collector”である」ことです。map(String::valueOf) で Stream<String> に変換してから、joining でつなげています。
二つ目は、「joining は prefix(先頭に付ける文字)と suffix(末尾に付ける文字)も指定できる」ことです。
String joined =
scores.stream()
.map(String::valueOf)
.collect(Collectors.joining(",", "[", "]"));
// 結果: [80,90,75]
Java三つ目は、「Stream の中でフィルタやソートをしながら join できる」ことです。
String joined =
scores.stream()
.filter(s -> s >= 80)
.sorted()
.map(String::valueOf)
.collect(Collectors.joining(","));
// 80,90
Java「加工しながら join する」というパターンは、業務でかなり頻出します。
SQL IN 句など「囲み文字付き」の join
'A','B','C' のような形を作る
SQL の IN 句などでは、IN ('A','B','C') のように、要素をシングルクォートで囲んでカンマ区切りにしたいことが多いです。
import java.util.List;
import java.util.stream.Collectors;
public class JoinForSql {
public static void main(String[] args) {
List<String> ids = List.of("u001", "u002", "u003");
String inValues =
ids.stream()
.map(id -> "'" + id + "'")
.collect(Collectors.joining(","));
String sql = "SELECT * FROM user WHERE id IN (" + inValues + ")";
System.out.println(sql);
// SELECT * FROM user WHERE id IN ('u001','u002','u003')
}
}
Javaここでの重要ポイントは二つです。
一つ目は、「map で“囲み文字付きの文字列”に変換してから join している」ことです。Collectors.joining 自体は「区切り」「前後の文字」は扱えますが、「各要素をどう加工するか」は map でやるのが基本です。
二つ目は、「SQL 組み立てでは、本来はプレースホルダ(?)+バインド変数を使うべき」という前提を忘れないことです。
ここでは join の例として書いていますが、実務では SQL インジェクション対策を必ず意識してください。
null や空要素をどう扱うかを決める
null を飛ばすか、そのまま "null" にするか
join 処理で地味にハマるのが、「null や空文字が混ざっている場合」です。
例えば、List<String> names = Arrays.asList("山田", null, "鈴木"); のようなケース。String.join(",", names) を呼ぶと、NullPointerException になります。
「null は飛ばしたい」なら、Stream でフィルタしてから join します。
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
List<String> names = Arrays.asList("山田", null, "鈴木");
String joined =
names.stream()
.filter(Objects::nonNull)
.collect(Collectors.joining(","));
// 山田,鈴木
Java「null も "null" として出したい」なら、String.valueOf を使う手もあります。
String joined =
names.stream()
.map(String::valueOf) // null → "null"
.collect(Collectors.joining(","));
// 山田,null,鈴木
Javaここでの重要ポイントは、
「null や空文字をどう扱うかを、join ユーティリティ側で決めておくと、呼び出し側が楽になる」ということです。
join 専用ユーティリティを作る
「毎回同じパターン」を名前付きにする
業務でよく使う join パターンは、ユーティリティにまとめてしまうと読みやすくなります。
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;
public final class Joins {
private Joins() {}
public static String joinComma(Collection<String> values) {
if (values == null || values.isEmpty()) {
return "";
}
return values.stream()
.filter(Objects::nonNull)
.collect(Collectors.joining(","));
}
public static String joinWithQuotes(Collection<String> values) {
if (values == null || values.isEmpty()) {
return "";
}
return values.stream()
.filter(Objects::nonNull)
.map(v -> "'" + v + "'")
.collect(Collectors.joining(","));
}
}
Java使い方のイメージです。
String csv = Joins.joinComma(names);
String inValues = Joins.joinWithQuotes(ids);
Javaここでの重要ポイントは三つです。
一つ目は、「null や空コレクションの扱いをユーティリティ側で統一している」ことです。
呼び出し側は「とりあえず join したい」とだけ書けばよく、毎回 null チェックを書かなくて済みます。
二つ目は、「joinComma や joinWithQuotes という名前で、“どう join するか”が一目で分かる」ことです。Collectors.joining(",") があちこちに散らばるより、意図が読みやすくなります。
三つ目は、「業務でよく使うパターン(CSV、SQL IN 句など)を“レシピ化”しておく」ことです。
毎回同じ書き方をコピペするより、ユーティリティに寄せた方が安全でメンテしやすくなります。
まとめ:join処理ユーティリティで身につけてほしい感覚
join処理は、
単に「文字列をつなげる」話ではなく、
「バラバラの要素を、人間や外部システムが読みやすい形に整える技術」です。
String.join で「そのままの文字列の集まり」を簡単につなげる。Collectors.joining と Stream を組み合わせて、「変換しながら join する」パターンを身につける。
null や空要素、囲み文字(クォート)などの扱いを、ユーティリティとして決めておく。
CSV、ログ、SQL など、「文字列の列挙」が必要な場面で、毎回同じ join パターンを再利用できるようにする。
あなたのコードのどこかに、StringBuilder で for 文を回しながら「最後のカンマを消す」ような処理があれば、
それを一度「join ユーティリティ」に置き換えられないか眺めてみてください。
その小さな置き換えが、
「文字列の列挙を、きれいで安全な形で扱えるエンジニア」への、
確かな一歩になります。

