【Java入門 実用編】文字列の基本的な操作(1) | 結合・分割・切り出し・含有の確認
2025.07.11
これまでの「Java入門」記事(#1 ~ #20)では、Javaの基本的な仕組みや動作に焦点を当ててきました。しかし、プログラミングにおいて頻繁に利用する文字列や数値、コレクションといったオブジェクトについては、その主だった利用方法のご紹介に留まっていました。
今回からの「Java入門 実用編」では、これらのオブジェクトをより深く、そして実践的に使いこなす方法を解説していきます。今回は、最も利用するオブジェクトである文字列の「結合」「分割」「切り出し」「含有の確認」といった操作について、具体的なコード例とともにご紹介します。
はじめに(前提条件)
当記事内の記述については、以下の前提条件とします。
・当記事内で「文字列」と記述されている場合、特に注記がなければ Java の String クラスのインスタンスを指すものとします。
・当記事内でクラスを指定せずにメソッド名が記述されている場合も、String クラスのメソッドを指すものとします。
文字列を結合する
+ 演算子で結合
Java で最も簡単に文字列を結合する方法は + 演算子を利用する方法です。
String strA = "AAA";
String strB = "BBB";
//「AAABBB」と出力される
System.out.println( strA + strB );
+ 演算子を連続で使用して、複数の文字列を結合することもできます。
String strA = "AAA";
String strB = "BBB";
String strC = "CCC";
//「AAABBBCCC」と出力される
System.out.println( strA + strB + strC );
+= 演算子(算術代入演算子)を使用して文字列を結合することもできます。
この場合、右辺の文字列が左辺の文字列の後方に連結されます。
String strA = "AAA";
String strB = "BBB";
strA += strB;
//「AAABBB」と出力される
System.out.println(strA);
+ 演算子または += 演算子を利用する場合、対象の文字列が null (またはnullリテラル)であっても例外は発生しません。ただしこの場合は、「null」という文字列リテラルに変換されて結合されることに注意が必要です。
String strA = "AAA";
String strNull = null;
// いずれも「AAAnull」と出力される
System.out.println(strA + strNull);
System.out.println(strA + null);
//「AAAnull」と出力される
strA += strNull;
System.out.println(strA);
以下のように null と null を結合するケースでも、変数 strNull の値は結合した値を代入した結果、 "nullnull" という文字列となってしまいますのでご注意ください。
String strNull = null;
//「nullnull」と出力される
strNull += null;
System.out.println(strNull);
+ 演算子では、文字列と数値など文字列以外の変数を結合することも可能です。このとき、文字列以外の値は String.valueOf メソッドで戻される文字列として結合されます。(null の場合に "null" という文字列リテラルとして結合されるのもこのためです)
またこの場合、戻される値は文字列となります。このため、文字列と結合した以降の + 演算子の動作は全て文字列としての結合となることに注意してください。
int int1 = 1;
int int10 = 10;
int int100 = 100;
// 「111円」と出力される(文字列にあたるまでは数値として演算される)
System.out.println(int100 + int10 + int1 + "円");
// 「¥100101」と出力される(先頭に文字列があるため、以降全て文字列として結合される)
System.out.println("¥" + int100 + int10 + int1 );
concat メソッド(文字列を後方に結合)
concat メソッドを利用して、文字列を結合することができます。concat メソッドでは、後方に結合したい文字列を引数に指定します。結合した結果を返すメソッドであるため、メソッドを呼び出した文字列変数自体の値は変わらないことに注意してください。
concat メソッド - Java 21 APIドキュメント
String strA = "AAA";
String strB = "BBB";
// strA に strB を結合
String concatStr = strA.concat(strB);
// 「AAABBB」と出力される
System.out.println(concatStr);
// strA 自体は「AAA」のまま
System.out.println(strA);
メソッドの戻り値が結合後の文字列なので、連続で concat メソッドを呼び出し、複数の文字列を連結させることも可能です。
String strA = "AAA";
String strB = "BBB";
String strC = "CCC";
String concatStr = strA.concat(strB).concat(strC);
// 「AAABBBCCC」と出力される
System.out.println(concatStr);
StringBuilder クラスを利用して結合
StringBuilder クラスは、文字の可変シーケンス(文字の連続)を扱うためのクラスです。インスタンスを作成して、append メソッドを利用することで文字列を結合させたり、位置を指定して一部を削ったりすることができます。
StringBuilder クラス - Java 21 APIドキュメント
StringBuilder クラスで文字列を結合するには、append メソッドを利用します。append メソッドは、文字列以外にも数値型やオブジェクト、StringBuilderを含む CharSequence などを引数としたオーバーロードメソッドが準備されています。
結合した結果を文字列として取得するには、toString メソッドを利用します。
String strA = "AAA";
String strB = "BBB";
int int100 = 100;
// StringBuilder クラスのインスタンスを作成
StringBuilder sb = new StringBuilder();
sb.append(strA);
sb.append(strB);
sb.append(int100); // String 以外も結合可能
//「AAABBB100」と出力される
System.out.println(sb.toString());
append メソッドの戻り値は 文字列を追加した StringBuilder インスタンス自身なので、連続で appendメソッドを呼び出すことも可能です。
String strA = "AAA";
String strB = "BBB";
int int100 = 100;
StringBuilder sb = new StringBuilder();
sb.append(strA).append(strB).append(int100);
//「AAABBB100」と出力される
System.out.println(sb.toString());
+ 演算子を利用して文字列を結合した場合、Java の内部処理ではこの StringBuilder クラスを利用して結合しています。
特に、ループ処理の中で何度も文字列を結合するなど、文字列を結合させる処理が何ヶ所にも分割されるようなケースでは、StringBuilder クラスのインスタンスを明示的に作成して利用することで、メモリの消費量を抑制し、処理のパフォーマンスを向上させることにつながります。
String.join メソッド(複数文字列を連結)
String.join メソッド(静的メソッド)を利用して、カンマ等の区切り文字とともに複数の文字列をまとめて結合することができます。引数の区切り文字に「空文字」を指定すれば、文字列だけが結合された結果を返すこともできます。
String.join メソッドは文字列の可変長引数(1個以降の任意の数の引数)を指定できます。
String strA = "AAA";
String strB = "BBB";
String strC = "CCC";
// 文字列をカンマ「,」で結合
String joinStr = String.join(",", strA, strB, strC);
//「AAA,BBB,CCC」と出力される
System.out.println(joinStr);
また、String.join メソッドは可変長引数のほかに、文字列の配列やコレクションを引数に指定することができます。特に配列や List などのコレクションに対しては、自分で繰り返し処理(ループ)を書くことなく簡潔に連結できるため、非常に相性が良いと言えるでしょう。
String[] xyz = {"XXX", "YYY", "ZZZ"};
// 配列内の値を全て結合
String joinStr = String.join(",", xyz);
//「XXX,YYY,ZZZ」と出力される
System.out.println(joinStr);
文字列を特定の文字列で分割する
split メソッド(文字列を分割する)
split メソッドを利用すると、文字列をカンマなどの特定の文字列で分割できます。分割した結果は、文字列の配列で返されます。
split メソッド - Java 21 APIドキュメント
String csvStr = "A,B,C,D";
// Stringの配列 {"A", "B", "C", "D"} が得られる
String[] strArray = csvStr.split(",");
//「A」「B」「C」「D」の4行が出力される
Arrays.stream(strArray).forEach( System.out::println );
引数で渡す区切り文字列は、単純な文字列ではなく「正規表現」として扱われます。このため、固定の文字列以外に、特定の正規表現に「合致する部分全体」で分割することも可能です。
String dateStr = "2025年1月23日";
String dateStrKana = "2025ねん1がつ23にち";
//「1文字以上の数字以外の文字の連続」を示す正規表現でsplit
String regex = "\\D+";
// どちらも {"2025", "1", "23"} が得られる
String[] dateArray = dateStr.split(regex);
String[] dateKanaArray = dateStrKana.split(regex);
// どちらも「2023」「1」「23」の3行が出力される
Arrays.stream(dateArray).forEach( System.out::println );
Arrays.stream(dateKanaArray).forEach( System.out::println
逆に、引数が正規表現として識別されるということは、正規表現で特殊な意味を持つ文字(例: .
*
+
?
[
]
(
)
{
}
^
$
|
\
など)を含む文字列で分割したい場合、そのまま split メソッドに渡しても意図する分割を行うことはできません。
これらの正規表現の特殊文字を含む文字列で分割したい場合は、その文字列の前後を「\\Q」と「\\E」で挟み込むことで、その文字列全体を正規表現ではない「固定の区切り文字」として扱うことが可能となります。
String regStr = "AAA|^.^|BBB|^.^|CCC";
// 正規表現で利用する文字を含む文字列で分割するための区切り文字列を準備
String exRegex = "\\Q" + "|^.^|" + "\\E";
//「|^.^|」の文字列で分割される
String[] exArray = regStr.split(exRegex);
//「AAA」「BBB」「CCC」の3行が出力される
Arrays.stream(exArray).forEach( System.out::println );
引数に区切り文字だけを指定する場合の注意点として、分割された最後の要素が空文字の場合は、その要素は配列に含まれません。さらに、最後からの要素に空文字が連続していた場合は、全て配列から取り除かれます。
このため、最後のいくつかの項目が空白である CSV 行データを分割した際などでは、想定より少ない要素数の配列が返るため注意が必要です。これらに対応するには、後述のオーバーロードメソッドを利用する必要があります。
String csvStrEmpty = "A,B,C,D,,,";
String csvStrFill = "A,B,C,D,,,G";
// 得られるStringの配列は {"A", "B", "C", "D"}
String[] strArrayEmpty = csvStrEmpty .split(",");
// 得られるStringの配列は {"A", "B", "C", "D", "", "", "G"}
String[] strArrayFill = csvStrFill .split(",");
split メソッドのオーバーロードメソッド
split メソッドでは第2引数(int limit)を指定することで、分割して作成される配列の内容を指定することが可能です。引数の値による動作の違いは以下の通りです。
limit に「0」を引き渡した場合は、区切り文字のみを引数に渡した場合と同じ動作(デフォルトの動作)となります。最後の要素が空文字だった場合に配列の要素に含まれないのも同じです。
String csvStrEmpty = "A,B,C,D,,,";
// 得られるStringの配列は {"A", "B", "C", "D"}
String[] strArrayEmpty = csvStrEmpty .split(",", 0);
limit に負の値(-1 など)を引き渡した場合は、実際に分割された要素数の配列が作成されます。この場合、最後の要素が空文字だった場合でも、配列の要素に含まれるため、CSVファイルの行データの分割などにも利用できます。
String csvStrEmpty = "A,B,C,D,,,";
// 得られるStringの配列は {"A", "B", "C", "D", "", "", ""}
String[] strArrayEmpty = csvStrEmpty .split(",", -1);
limit に正の値を指定した場合は、作成する配列の要素数の上限が指定されます。文字列は先頭から分割され、指定した要素数に達するか、それ以上分割できない場合は、区切り文字を含めた残りの文字列が、最後の要素にすべて格納されます。
逆に、実際に分割される要素数より大きなlimit値を指定した場合は、通常通り(limitに負の値を指定した場合と同様に)すべての要素が分割された配列が作成されます。この場合、limit 指定した値よりも少ない要素数の配列である場合があることに注意してください。
また、この場合も、最後の要素が空文字であっても配列の要素として格納されます。
String csvStrEmpty = "A,B,C,D,,,";
// 得られるStringの配列は {"A", "B", "C,D,,,"}
String[] strArrayEmpty = csvStrEmpty .split(",", 3);
// 得られるStringの配列は {"A", "B", "C", "D", "", "", ""}
String[] strArrayEmpty2 = csvStrEmpty .split(",", 10);
文字列の一部分を切り出す
substring メソッド(一部を切り出す)
substring メソッドは、位置を指定して文字列の一部(または全部)を切り出すことができます。
substring メソッド - Java 21 APIドキュメント
引数に切り出しを開始する位置(先頭を0とするインデックス値)だけを指定した場合は、その位置から文字列の最後までを切り出します。
// インデックスは[0]"A"、[1]"B"、[2]"C"、… [25]"Z"
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//「BCDEFGHIJKLMNOPQRSTUVWXYZ」と出力される
System.out.println(alphabet.substring(1));
//「XYZ」と出力される
System.out.println(alphabet.substring(23));
切り出しの開始位置に加え、2つ目の引数に切り出しの終了位置(インデックス)を指定することもできます。終了位置を指定した場合は、指定した位置の1つ前までの文字を切り出します。2つ目の引数が「切り出す文字数ではない」ことに注意してください。
// [0]"2"、[1]"0"、[2]"2"、[3]"5"、[4]="0"、[5]="1"、[6]=2、[7]=3
String ymd = "20250123";
String y = ymd.substring(0, 4);
String m = ymd.substring(4, 6);
String d = ymd.substring(6);
// 「year=2025,month=01,day=23」と出力
System.out.println("year=" + y + ",month=" + m + ",day=" + d);
文字列を含むかどうか判定する
contains メソッド(指定した文字列を含むかを判定)
contains メソッドは、文字列の中に指定した文字列を含んでいるかどうかを取得できます。
contains メソッド - Java 21 APIドキュメント
String domain = "knovus.site";
// 元の文字列に含まれる場合は true
System.out.println(domain.contains(".site"));
// 元の文字列に含まれない場合は false
System.out.println(domain.contains(".com"));
contains メソッドの引数は「CharSequence」インターフェイスですので、String クラス以外の実装クラスである StringBuilder クラスなどのインスタンスも、そのまま引数に指定できます。
String domain = "knovus.site";
StringBuilder sb = new StringBuilder();
sb.append("novus")
// contains メソッドの引数に StringBuilder のインスタンス(sb)をそのまま指定
if(domain.contains(sb)) {
System.out.println("「novus」が含まれています");
} else {
System.out.println("「novus」は含まれていません");
}
文字列の含まれる位置を取得する
indexOf メソッド(最初の出現位置を取得)
indexOf メソッドでは、指定した文字・文字列を、対象の文字列が最初に含まれている位置(0から始まるインデックス)を返します。指定した文字・文字列が含まれていない場合は「-1」が返されます。
indexOf メソッド - Java 21 APIドキュメント
String strABC = "ABCABCABC";
//「2」が出力される
System.out.println(strABC.indexOf("C"));
//「-1」が出力される
System.out.println(strABC.indexOf("X"));
検索したい文字列が複数文字(2文字以上)の場合、その文字列全体が最初に一致する部分の先頭の文字のインデックスが返されます
String strABC = "ABCABCABC";
// 「1」が出力される
System.out.println(strABC.indexOf("BC"));
また、第2引数にインデックスを指定することで、指定したインデックス以降で最初に一致した箇所の位置を取得することもできます。
String strABC = "ABCABCABC";
// 「5」が出力される
System.out.println(strABC.indexOf("C", 3));
// 「4」が出力される
System.out.println(strABC.indexOf("BC", 4));
さらに第3引数として検索を終了するインデックスを指定することで、検索する範囲(開始位置、終了位置)を指定することもできます。終了位置も指定した場合は、指定したインデックスの1つ前までに検索対象の文字列が含まれていたときに、その開始位置を返します。
String strABC = "ABCABCABC";
//「-1」が出力される(検索範囲は0~1番目の文字列「AB」)
System.out.println(strABC.indexOf("C", 0, 2));
//「5」が出力される(検索範囲は3~5番目の文字列「ABC」)
System.out.println(strABC.indexOf("C", 3, 6));
第3引数を指定し、かつ検索したい文字列が複数文字の場合、先頭の文字だけでなく、全てが指定した範囲で合致する必要があることに注意が必要です。
String strABC = "ABCABCABC";
//「-1」が出力される(検索範囲は0~1番目の文字列「AB」)
System.out.println(strABC.indexOf("BC", 0, 2));
//「-1」が出力される(検索範囲は2~4番目の文字列「CAB」)
System.out.println(strABC.indexOf("BC", 2, 5));
//「4」が出力される(検索範囲は3~5番目の文字列「ABC」)
System.out.println(strABC.indexOf("BC", 3, 6));
lastIndexOf メソッド(最後の出現位置を取得)
lastIndexOf メソッドでは、指定した文字・文字列を、対象の文字列が最後に含まれている位置(0から始まるインデックス)を返し、含まれていなかった場合は「-1」が返されます。
また、indexOf メソッドと同様に、引数で指定した文字列が複数文字(2文字以上)の場合は「最後に全て一致する部分の1文字目の位置」が返却されます。
String strABC = "ABCABCABC";
//「6」が出力される
int idxA = strABC.lastIndexOf("A");
System.out.println(idxA);
//「-1」が出力される
int idxZ = strABC.lastIndexOf("Z");
System.out.println(idxZ);
//「4」が出力される
int idxBCA = strABC.lastIndexOf("BCA");
System.out.println(idxBCA);
lastIndexOf メソッドも、2つ目の引数にインデックスを指定することで、指定したインデックス以前(指定インデックスを含む、より若いインデックスの範囲)で、指定した文字や文字列が最後に一致した箇所の位置を返します。
String strABC = "ABCABCABC";
// 5~7番目が一致しているので「5」が返される
int idx = strABC.lastIndexOf("CAB", 6);
System.out.println(idx);
上記のサンプルコードのように、最後に「CAB」に一致する部分は「ABCABCABC」(5~7番目)ですが、第2引数に「6」と指定した際も「5」が返されます。
これは、lastIndexOf メソッドが指定されたインデックスを検索の終了点として、そこから逆向きに検索を開始するためです。検索範囲のすべてが指定したインデックス以前に収まるとは限らないため、この挙動には注意が必要です。