山崎屋の技術メモ

IT業界で働く中で、気になること、メモしておきたいことを書いていきます。

Java 末尾に現れる文字列を置換

String 文字列の話です。

ある文字列中の末尾に現れる正規表現文字列を置換します。

String#replaceAll


String クラスの replaceAll を使用する方法。

public class Main {
	public static void main(String[] args) {
		String str = "hogehoge";
		System.out.println(str.replaceAll("hoge$", "fuga"));
	}
}

[hogehoge] という文字列の最後の hoge だけを fuga に置換して出力しています。

出力結果

hogefuga

replaceAll メソッドに渡している第一引数の [hoge$] の $ が文字列の終端を表しているため、最後の hoge だけが置換されます。

String#replaceFirst

最初に一致する文字列を置換するはずの replaceFirst を使用しても同様の結果となります。

public class Main {
	public static void main(String[] args) {
		String str = "hogehoge";
		System.out.println(str.replaceFirst("hoge$", "fuga"));
	}
}

結局、正規表現中に $ があるので、末尾の hoge しか置換しません。

どちらが早い?

replaceAll と replaceFirst の 2 種類の方法を紹介しましたが、速度的にはどちらが早いのでしょうか?

「100 万回文字列の置換をする」を 1 セット として 10 セットで試してみました。

public class Main {
	public static void main(String[] args) {
		String str = "hogehoge";

		for (int i = 0; i < 10; i++) {
			// replaceAll
			System.gc();
			final List<String> list = new ArrayList<>();
			long start = System.currentTimeMillis();
			IntStream.range(0, 1_000_000).forEach(s -> list.add(str.replaceAll("hoge$", "fuga")));
			long end = System.currentTimeMillis();
			System.out.println((i + 1) + "回目 replaceAll[ " + (end - start) + " ]ms");

			// replaceFirst
			System.gc();
			final List<String> list2 = new ArrayList<>();
			long start2 = System.currentTimeMillis();
			IntStream.range(0, 1_000_000).forEach(s -> list2.add(str.replaceFirst("hoge$", "fuga")));
			long end2 = System.currentTimeMillis();
			System.out.println((i + 1) + "回目 replaceFirst[ " + (end2 - start2) + " ]ms");
		}
	}
}

結果は次のようになりました。

メソッド 1 回目 2 回目 3 回目 4 回目 5 回目 6 回目 7 回目 8 回目 9 回目 10 回目
replaceAll 1437 929 937 993 919 908 927 933 925 908
replaceFirst 1038 869 928 873 896 893 872 886 863 895

わずかに replacFirst が早いようですが、誤差の範囲ですね。VM の実装によって結果が入れ替わる可能性もあります。

どちらを使ってもいいでしょう。

それでは。


駆け出しのころはこれで勉強しました。↓↓↓

やさしいJava 第6版 (「やさしい」シリーズ)

やさしいJava 第6版 (「やさしい」シリーズ)