Redditで見かけたこちらの記事。
記事の内容を一言でまとめると
「これまでは常に正規表現でパースしていたが、簡単なパターン文字列は正規表現無しで処理するようにしたから速い」
なのですが、実際にどういうコードになったのか気になったので見てみました。
該当のコードは以下。
private List<FormatString> parse(String s) { ArrayList<FormatString> al = new ArrayList<>(); int i = 0; int max = s.length(); Matcher m = null; // create if needed while (i < max) { int n = s.indexOf('%', i); if (n < 0) { // No more format specifiers, but since // i < max there's some trailing text al.add(new FixedString(s, i, max)); break; } if (i != n) { // Previous characters were fixed text al.add(new FixedString(s, i, n)); } i = n + 1; // ★ 次の文字を読む if (i >= max) { // Trailing % throw new UnknownFormatConversionException("%"); } char c = s.charAt(i); if (Conversion.isValid(c)) { // ★ %の次の文字がパターン文字列だったらこれで終わり al.add(new FormatSpecifier(c)); i++; } else { // ★ 簡単なパターン文字列でないなら従来通り正規表現 if (m == null) { m = fsPattern.matcher(s); } // We have already parsed a '%' at n, so we either have a // match or the specifier at n is invalid if (m.find(n) && m.start() == n) { al.add(new FormatSpecifier(s, m)); i = m.end(); } else { throw new UnknownFormatConversionException(String.valueOf(c)); } } } return al; }
「★」のところがポイントです。 %s
とか %d
のように、 %?
のパターンだけ特別扱いしています。 %.3d
とかはダメ。
大抵は単純なパターン文字列だけなので、結果的に「速い」と言うことですね。
Formatterクラスについて
あとは、Formatterクラス自体をキャッシュ可能にしてくれれば言うことはないのですが、、
何故そう言う実装なのか知りませんが、FormatterクラスはFormatter#format(String format, Object... args)
を呼ぶ度に上記のパターンパースが走ります。java.util.regex.Patternみたいに、コンパイル済みのパターンを置いておける実装になってないんです。謎。