行分割は「1つの長い文字列を“行ごと”に扱えるようにする」技
業務システムでは、ログ、テキストファイル、メール本文、エラーメッセージなど、
「複数行の文字列」を扱う場面がたくさんあります。
でも、Javaの String はあくまで「1本の文字列」です。
そのままだと「何行目か」「1行ずつ処理したい」といったことがやりにくい。
そこで必要になるのが 行分割(line split) です。
「改行コードで文字列を区切って、行ごとの配列やリストにする」ことで、
1行ずつループしたり、特定の行だけ取り出したりできるようになります。
行分割で一番大事なポイントは「改行コードの違い」
OSごとに改行コードが違う問題
まず、行分割で絶対に押さえておきたいのが、
「改行コードは1種類じゃない」 という事実です。
代表的には次の3つがあります。
LF(\n)… Unix系(Linux, macOSなど)CRLF(\r\n)… WindowsCR(\r)… 古いMac(今はほぼ見ないが、データとして残っていることはある)
もし、行分割を単純に split("\n") でやってしまうと、"\r\n" の \r が行末に残ってしまったり、"\r" だけの改行を認識できなかったりします。
業務で外部ファイルや他システムからのデータを扱うなら、
「LF も CRLF も CR も、全部“改行”として扱う」 という前提で行分割を書くのが安全です。
正攻法:正規表現で「どの改行コードでも分割できる」ようにする
split("\R")(Java 8以降)を使う
Java 8以降なら、実はかなり便利なやり方があります。
正規表現の \R は「任意の改行シーケンス」を意味します。
つまり、LF でも CRLF でも CR でも、全部まとめて「改行」として扱ってくれます。
public final class LineSplitter {
private LineSplitter() {}
public static String[] splitLines(String text) {
if (text == null || text.isEmpty()) {
return new String[0];
}
return text.split("\\R");
}
}
Java使い方はこうです。
String text = "1行目\n2行目\r\n3行目\r4行目";
String[] lines = LineSplitter.splitLines(text);
for (String line : lines) {
System.out.println("[" + line + "]");
}
Java出力イメージはこうなります。
[1行目]
[2行目]
[3行目]
[4行目]
ここで重要なのは、「改行コードの違いを意識せずに済む」ということです。split("\\R") を使えば、どのOS由来の改行でも、きれいに行ごとに分割できます。
Java 7以前や \R を使いたくない場合
もし \R を使えない状況なら、"\r\n" | "\n" | "\r" をまとめて扱う正規表現を自分で書きます。
public static String[] splitLinesLegacy(String text) {
if (text == null || text.isEmpty()) {
return new String[0];
}
return text.split("\\r\\n|\\n|\\r");
}
Javaやっていることは \R と同じで、
「CRLF か LF か CR のどれかで分割する」という意味です。
行分割ユーティリティを「List<String>」で返す形にする
配列よりリストの方が扱いやすい場面が多い
split は配列を返しますが、
業務コードでは List<String> の方が扱いやすいことが多いです。
例えば、ストリームAPIで処理したり、forEach を使ったり、
後から行を追加・削除したりしやすくなります。
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class LineSplitter {
private LineSplitter() {}
public static List<String> splitLinesToList(String text) {
if (text == null || text.isEmpty()) {
return Collections.emptyList();
}
String[] array = text.split("\\R");
return Arrays.asList(array);
}
}
Java使い方はこうです。
String text = "A\nB\r\nC";
List<String> lines = LineSplitter.splitLinesToList(text);
lines.forEach(line -> System.out.println("[" + line + "]"));
Javaここでのポイントは、「null や空文字のときに“空のリスト”を返す」という方針です。
これにしておくと、呼び出し側で
for (String line : LineSplitter.splitLinesToList(text)) {
...
}
Javaと書いても、nullチェックなしで安全に回せます。
行末の空行をどう扱うかを決める
最後が改行で終わる場合、「空行」を1行として扱うか?
例えば、こんな文字列を考えます。
String text = "1行目\n2行目\n";
Java最後に改行が入っているので、
「3行目は空行」とみなすかどうか、という問題が出てきます。
split("\\R") は、末尾の空行を基本的には無視します。
String text = "1行目\n2行目\n";
String[] lines = text.split("\\R");
System.out.println(lines.length); // 2
Java「最後の空行も1行として扱いたい」という要件がある場合は、
少し工夫が必要です。
一つのやり方は、「自分でループしながら行を切り出す」方法です。
ただ、業務でそこまで厳密に「末尾の空行」を扱う場面は多くありません。
ここで大事なのは、
「split の挙動を知ったうえで、“自分のシステムではどう扱うか”を決めること」 です。
実務での行分割の使いどころ
例1:ログ文字列を行ごとに処理する
例えば、1つの文字列にまとめられたログを、
行ごとに処理したい場面を考えます。
String logText = """
ERROR: something bad
WARN: be careful
INFO: all good
""";
for (String line : LineSplitter.splitLinesToList(logText)) {
if (line.startsWith("ERROR")) {
System.out.println("エラー行: " + line);
}
}
Javaここでは、行分割ユーティリティのおかげで、
「ログ全体」ではなく「ログの1行1行」を自然に扱えるようになっています。
例2:テキストエリアの入力を1行ずつ検証する
ユーザーがテキストエリアに複数行のデータを入力する画面を考えます。
例えば、「1行に1つずつメールアドレスを入力してください」というようなケースです。
サーバ側では、こんな感じで使えます。
String input = request.getParameter("emails");
List<String> lines = LineSplitter.splitLinesToList(input);
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i).trim();
if (line.isEmpty()) {
continue; // 空行はスキップ
}
if (!EmailValidator.isValid(line)) {
errors.add((i + 1) + "行目のメールアドレスが不正です: " + line);
}
}
Javaここでのポイントは、「行番号(i + 1)を使ってエラーメッセージを出せる」ことです。
行分割しておくことで、「何行目に問題があるか」をユーザーに丁寧に伝えられます。
まとめ:行分割ユーティリティで身につけたい感覚
行分割は、「1つの長い文字列を“行ごと”に扱えるようにする」ための基本テクニックです。
押さえておきたいのは次の感覚です。
改行コードは \n だけではなく、\r\n や \r もあるsplit("\\R")(または \\r\\n|\\n|\\r)で、どの改行コードでも分割できるようにする
配列ではなく List<String> で返すと、業務コードで扱いやすい
null や空文字のときは「空の配列/リスト」を返すと安全
末尾の空行をどう扱うかは、要件に応じて決める
もしあなたのコードのどこかに、
String[] lines = text.split("\n");
Javaのような行がそのまま書かれていたら、
それを題材にして、ここで作った LineSplitter.splitLines や splitLinesToList に置き換えてみてください。
その小さな改善が、
「OSや外部システムの違いに強い、堅牢な文字列処理」を書けるエンジニアへの、確かな一歩になります。
