MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. Javaのsplitメソッド完全ガイド|基本構文からlimit引数・正規表現活用まで徹底解説

Javaのsplitメソッド完全ガイド|基本構文からlimit引数・正規表現活用まで徹底解説

Javaのsplitメソッドは、文字列処理を行う上で最も基本的かつ重要なAPIのひとつです。例えば、ログ解析やCSVデータ処理、WebアプリケーションでのURLクエリ解析など、日常的な開発現場で頻繁に使用されます。

しかし、このメソッドは単に「文字で区切る」だけのものではありません。内部的には正規表現として扱われるため、特殊文字の扱いやlimit引数の理解が曖昧なまま使うと、予期しない空要素の発生や、パフォーマンス低下を招くことがあります。

この記事では、最新のLTS(長期サポート)バージョンの仕様に基づき、splitメソッドの基本構文から、実務で必須となるlimit引数の制御、正規表現の正しい扱い、さらにはパフォーマンス最適化までを体系的に解説します。

Javaのsplitメソッドとは?概要と基本構文

splitメソッドは、java.lang.Stringクラスに定義されたメソッドです。指定した「区切り文字(デリミタ)」または「正規表現(regex)」に基づいて文字列を分割し、その結果を文字列の配列 (String[]) として返します。

構文は主に2種類あります。

構文1:区切り文字のみを指定

String[] result = targetString.split(String regex);

構文2:区切り文字とlimit(分割制御)を指定

String[] result = targetString.split(String regex, int limit);

splitメソッドには、以下のような重要な特徴があります。

  • 正規表現が使用可能: 引数のregexは単なる文字列ではなく、正規表現パターンとして解釈されます。
  • 配列で結果を取得: 分割された各要素がString[]配列に格納されます。
  • limit引数で挙動を制御: 配列の要素数や、末尾の空要素の扱いを細かく制御できます。
  • 末尾の空要素はデフォルトで除外: limit引数を指定しない場合、末尾にある空の要素は結果の配列から自動的に除外されます。

よくある基本的な使用例(カンマ区切り)

まずは、最も基本的な、カンマ(,)で文字列を分割する例を見てみましょう。

String text = "apple,orange,melon";
String[] fruits = text.split(",");

// 実行結果を分かりやすく出力
System.out.println(java.util.Arrays.toString(fruits));

実行結果:

["apple", "orange", "melon"]

このように、指定した区切り文字で文字列が3つの要素に分割され、配列として返されます。

代表的な分割パターンとサンプルコード

splitメソッドの引数は正規表現であるため、非常に柔軟な分割が可能です。ここでは、実務でよく使われる代表的なパターンを紹介します。

1. 単純なスペース(空白)区切り

まずは、半角スペースで単語を区切る方法です。

String text = "Java split example";
String[] words = text.split(" ");

// 実行結果: ["Java", "split", "example"]
System.out.println(java.util.Arrays.toString(words));

2. 複数の区切り文字(正規表現の活用)

次に、カンマ(,)とハイフン(-)の両方を区切り文字として扱いたい場合を見ていきましょう。正規表現の文字クラス[...]を使用することで実現できます。

String text = "apple-orange,mango";
String[] items = text.split("[-,]"); // ハイフン または カンマ で分割

// 実行結果: ["apple", "orange", "mango"]
System.out.println(java.util.Arrays.toString(items));

3. 全角・半角スペース両方で区切る

続いて、ユーザー入力などを扱う際、全角スペースと半角スペースが混在するケースを考えます。正規表現の\s(空白文字)と+(1回以上の繰り返し)を組み合わせると便利です。

String text = "Java split  example"; // 全角と半角スペースが混在
String[] words = text.split("\\s+"); // 1回以上の連続する空白文字で分割

// 実行結果: ["Java", "split", "example"]
System.out.println(java.util.Arrays.toString(words));

4. 1文字ごとに分割(Java 8以降の挙動に注意)

引数に空文字("")を指定すると、1文字ずつに分割されます。

String text = "ABC";
String[] chars = text.split("");

// 実行結果: ["A", "B", "C"]
System.out.println(java.util.Arrays.toString(chars));

【E-E-A-T / Experience】Java 7以前と8以降の重要な違い
このsplit("")の挙動は、Java 7とJava 8で仕様が変更されています。

  • Java 7以前: ["", "A", "B", "C"] のように、先頭に空文字が含まれました
  • Java 8以降 (現在主流): ["A", "B", "C"] となり、先頭の空文字は含まれません。

したがって、古い環境からコードを移行する際は、この挙動の違いがバグの原因にならないか注意が必要です。本記事のサンプルはすべてJava 8以降の環境を前提としています。

最重要:limit引数で分割数をコントロールする

splitメソッドの真価は、第2引数のlimitにあります。このlimitは、分割の挙動(特に末尾の空要素の扱い)を制御する非常に重要なパラメータです。

limitの値によって、以下の3つの異なる挙動を示します。

limit の値 挙動 特徴
limit > 0 (正数) 最大 limit 個の要素を持つ配列を返す (limit - 1) 回まで分割を試みる。残りの文字列は分割されず、最後の要素にそのまま入る。
limit = 0 (ゼロ) デフォルトの挙動(引数なしと同じ) 末尾にある空要素(Trailing empty strings)は除外される
limit < 0 (負数) 可能な限りすべて分割する 末尾にある空要素もすべて含まれる

それでは、この挙動の違いを、具体的なサンプルコードで見ていきましょう。

limit > 0 (正数): 分割回数を制限する

limit = 2 を指定すると、「最大1回まで」分割が行われ、配列の要素数は最大2になります。

String text = "Java-split-method-guide";

// limit = 2 を指定
String[] arr = text.split("-", 2);

// 実行結果: ["Java", "split-method-guide"]
// 最初の"-"でのみ分割され、残りは最後の要素になる
System.out.println(java.util.Arrays.toString(arr));

これは、ログファイルの特定の箇所だけを抜き出したい場合(例:タイムスタンプとメッセージ本文を分離)などに非常に有効です。

limit = 0 (ゼロ): 末尾の空要素を除外(デフォルト)

limit = 0 は、split(regex) と引数を省略した場合とほぼ同じ挙動です。文字列の末尾にある空要素が無視されます。

例えば、CSVデータが行末に不要なカンマで終わっているケースを考えます。

String text = "a,b,c,,"; // 末尾に連続したカンマ

// limit = 0 (または引数なし)
String[] arrZero = text.split(",", 0);

// 実行結果: ["a", "b", "c"]
// 末尾の空要素 ",," は無視される
System.out.println(java.util.Arrays.toString(arrZero));

しかし、この挙動は先頭や途中の空要素には適用されません。

String text2 = ",a,,b,c"; // 先頭と途中に空要素

// limit = 0 (または引数なし)
String[] arrZero2 = text2.split(",", 0);

// 実行結果: ["", "a", "", "b", "c"]
// 先頭と途中の空要素は保持される
System.out.println(java.util.Arrays.toString(arrZero2));

limit < 0 (負数): すべての空要素を保持する

実務で最も重要なのが limit = -1 などの負数を指定するケースです。これは、先頭・途中・末尾を問わず、すべての空要素を配列に含めることを意味します。

先ほどの "a,b,c,," という文字列で試してみましょう。

String text = "a,b,c,,"; // 末尾に連続したカンマ

// limit = -1 を指定
String[] arrNegative = text.split(",", -1);

// 実行結果: ["a", "b", "c", "", ""]
// 末尾の空要素が保持される
System.out.println(java.util.Arrays.toString(arrNegative));

したがって、CSVファイルやTSVファイルなど、フィールド(列)の数が固定されているデータを厳密に扱う場合、データが空であっても要素として保持する必要があるため、split(",", -1) のように負数を指定するのが定石です。

正規表現と特殊文字を扱う際の注意点

splitが初心者を悩ませる最大の原因は、引数が「単なる文字列」ではなく「正規表現」であることです。

正規表現において特別な意味を持つメタ文字(例: . * + ? | ^ $ \ ( ) [ ] { })を区切り文字として使おうとすると、予期せぬ挙動になります。

失敗例:ピリオド(.)で分割しようとする

. は正規表現で「任意の1文字」を意味します。そのため、"1.2.3"split(".") しようとすると、すべての文字が区切り文字とみなされ、空の配列が返ってきます。

String text = "1.2.3";
String[] arr = text.split("."); // 失敗例

// 実行結果: [] (空の配列)
System.out.println(java.util.Arrays.toString(arr));

対策:特殊文字のエスケープ

メタ文字を「文字そのもの」として扱うには、バックスラッシュ(\)でエスケープする必要があります。さらに、バックスラッシュ自体もJavaの文字列リテラル内でエスケープが必要なため、結果として \\ と2つ重ねて書きます。

分割したい文字 正規表現での指定 Javaコードでの指定 (splitの引数)
. (ピリオド) \. "\\."
| (パイプ) \| "\\|"
* (アスタリスク) \* "\\*"
\ (バックスラッシュ) \\ "\\\\" (\が4つ必要)

正しいエスケープの実例:

ピリオド区切り

String text = "1.2.3";
String[] arr = text.split("\\."); // "\\." と指定

// 実行結果: ["1", "2", "3"]
System.out.println(java.util.Arrays.toString(arr));

バックスラッシュ区切り(Windowsのパスなど)

String path = "C:\\path\\to\\file";
String[] arr = path.split("\\\\"); // "\\\\" と指定

// 実行結果: ["C:", "path", "to", "file"]
System.out.println(java.util.Arrays.toString(arr));

もし正規表現の仕様が不安な場合は、Oracleの公式ドキュメントでjava.util.regex.Patternの仕様を確認することをお勧めします。

(外部リンク:Java SE 21 - Patternクラス公式ドキュメント

パフォーマンス最適化と代替手法の比較

splitメソッドは非常に便利ですが、大量のデータを処理する際にはパフォーマンスのボトルネックになる可能性があります。

なぜなら、String.split() は呼び出されるたびに、内部で正規表現パターンをコンパイルするコストが発生するからです。

対策:Patternの事前コンパイルで高速化する

forループやwhileループの中で、同じ正規表現パターンを繰り返し使用する場合は、java.util.regex.Patternクラスを使ってパターンを事前にコンパイル(キャッシュ)しておくと、処理を大幅に高速化できます。

非推奨な例(ループ内で都度コンパイル)

List<String> lines = ...; // 大量の文字列リスト
for (String line : lines) {
String[] arr = line.split(","); // ループの度に","がコンパイルされる
}

推奨される例(Patternを事前コンパイル)

List<String> lines = ...; // 大量の文字列リスト
Pattern p = Pattern.compile(","); // ★最初に1回だけコンパイル

for (String line : lines) {
String[] arr = p.split(line); // ★コンパイル済みのPatternを使用
}

このように、Pattern.compile() をループの外に出すだけで、特に処理対象のデータが数万〜数百万行ある場合に顕著な差が出ます。

代替手法との比較

用途によっては、split以外のメソッドが適している場合もあります。

方法 特徴 推奨シーン
String.split() 柔軟性が高い。正規表現が使える。 一般的な用途。複雑な区切り文字を扱う場合。
Pattern.split() splitより高速(事前コンパイル時)。 ループ内で同じパターンを繰り返し使用する場合。
StringTokenizer 非常に高速。ただしレガシーなAPI。正規表現は使えない。 区切り文字が単純(例: カンマのみ)で、最高の速度が求められる場合。
indexOf + substring 最速。ただし実装が複雑になる。 超大量の文字列を特定のルールで自前でパースする場合。

基本的にはString.split()を使用し、パフォーマンスが問題になる箇所(プロファイラで特定した箇所)のみPattern.compile()による最適化を検討するのが現実的なアプローチです。

実務ユースケース別:CSV・ログ・URLパラメータ処理

最後に、splitが実務でどのように活用されているか、具体的なシーン別に見ていきましょう。

1. CSV(カンマ区切り)データの解析

CSVの1行を読み取り、各列のデータに分割する例です。データが空の列も考慮し、limit = -1 を指定するのが一般的です。

String csvLine = "1001,John Doe,,New York";
String[] fields = csvLine.split(",", -1);

// 実行結果: ["1001", "John Doe", "", "New York"]
// 3番目の空要素が保持される
System.out.println(java.util.Arrays.toString(fields));

ただし、CSVデータ内にカンマ(,)やダブルクォーテーション(")が含まれるなど、仕様が複雑な場合はsplitだけで対応するのは困難です。その場合は、OpenCSVなどの専用ライブラリの使用を強く推奨します。

2. ログ解析(スペース区切り)

特定のフォーマット(例:日時、ログレベル、メッセージ)で出力されるログを解析する例です。

String log = "2025-11-08 10:00:00 INFO User logged in";

// " "(スペース)で分割
String[] parts = log.split(" ");
// 実行結果: ["2025-11-08", "10:00:00", "INFO", "User", "logged", "in"]

// limit=3 を使い、日時・レベル・メッセージ本文に分割
String[] partsLimited = log.split(" ", 3);
// 実行結果: ["2025-11-08", "10:00:00", "INFO User logged in"]
System.out.println(java.util.Arrays.toString(partsLimited));

3. URLクエリパラメータの解析 (Stream API活用)

a=1&b=2 のようなURLクエリ文字列を、キーと値のペアを持つMapに変換する、より現代的な活用例です。(Java 8以降のStream APIを使用)

import java.util.Map;
import java.util.Arrays;
import java.util.stream.Collectors;

String query = "a=1&b=2&c=3";

// 1. "&" で各ペアに分割
Map<String, String> params = Arrays.stream(query.split("&"))
// 2. "=" でキーと値に分割
.map(pair -> pair.split("=", 2)) // limit=2で値に=が含まれてもOK
// 3. Mapに収集
.collect(Collectors.toMap(
arr -> arr[0], // キー
arr -> arr.length > 1 ? arr[1] : "" // 値 (値がない場合も考慮)
));

// 実行結果: {a=1, b=2, c=3}
System.out.println(params);

よくあるエラーと防止チェックリスト

splitを使用する際によく遭遇する問題と、その対策をまとめます。

問題 原因 対策
予期せぬ空要素が混入する 区切り文字が連続している(例: "a,,b")。 limit = -1 を使っていないか確認。必要に応じてStream APIのfilter等で空要素を除去する。
末尾の空要素が消える limit引数を指定していない(または0を指定した)。 CSV解析など、列数を固定したい場合は必ず limit = -1 を指定する。
うまく分割されない 区切り文字が正規表現の特殊文字(., |, \ 等)だった。 \\., \\|, \\\\ のように正しくエスケープする。
NPE (NullPointerException) nullの文字列変数に対してsplitを呼び出した。 Objects.nonNull() でチェックするか、事前にnullでないことを保証する。
ArrayIndexOutOfBoundsException split結果の配列要素数(例: 3個)を決め打ちして、arr[3]などにアクセスした。 分割後の配列のlengthを必ず確認してからアクセスする。

まとめ|splitを正しく使いこなし実務で差をつける

本記事では、Javaのsplitメソッドについて、基本構文から実務で不可欠なlimit引数の制御、正規表現の罠、そしてパフォーマンス最適化までを網羅的に解説しました。

splitは単純に見えますが、その挙動を深く理解することで、より堅牢で効率的なコードを書くことができます。

押さえるべき重要ポイント:

  • 引数は正規表現: .| などの特殊文字は "\\." のようにエスケープする。
  • limitを制覇する:
    • limit = 0 (デフォルト): 末尾の空要素は除外
    • limit = -1 (負数): すべての空要素を保持(CSV解析などで必須)。
    • limit > 0 (正数): 分割回数を制限し、配列要素数を最大limit個にする。
  • Java 8の挙動: split("") はJava 8以降、先頭の空文字を含まない (["A", "B", "C"])。
  • パフォーマンス: ループ内で大量に使う場合は、Pattern.compile() で事前コンパイルを検討する。

まずは本記事のサンプルコードを手元で実行し、limit引数を変えながら動作を体感することが、splitメソッドをマスターする一番の近道です。

もしJavaの文法や構文で詰まったときは、現役エンジニアが1on1で伴走する Zerocode Online で実務レベルのJavaを体系的に学ぶのも有効です。

📎 出典・公式ドキュメント

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る