【Java学習|実務向け】Java 11の新機能:Pattern.asMatchPredicate()を活用したエレガントな文字列判定

導入

Javaの正規表現といえば、古くから `Pattern` クラスと `Matcher` クラスを組み合わせて利用するのが一般的でした。しかし、単に「文字列が正規表現に完全に一致するか」を確認したいだけのケースで、毎回 `matcher.matches()` を呼び出すのは、コードの記述量が増えるだけでなく、可読性を損なう要因にもなります。
Java 11で導入された `Pattern.asMatchPredicate()` は、正規表現を `java.util.function.Predicate` 型に変換するメソッドです。これにより、Stream APIとの親和性が劇的に向上し、より簡潔でモダンなJavaプログラミングが可能になります。

基礎知識

`Predicate` は、引数を1つ受け取り、boolean値を返す関数型インターフェースです。Java 8以降、フィルタリングや条件判定において標準的に利用されています。
一方、`Pattern` クラスは正規表現をコンパイルしたオブジェクトです。通常は `pattern.matcher(input).matches()` とすることで、文字列全体が正規表現にマッチするかを判定します。`asMatchPredicate()` は、内部的にこの「全体一致判定」を行う関数を生成し、`Predicate` として返却する仕組みです。

実装/解決策

`asMatchPredicate()` の最大のメリットは、Stream APIの `filter()` メソッド等に直接渡せる点にあります。従来の匿名クラスやラムダ式で `matcher` を生成していた冗長なコードを排除し、宣言的な記述に置き換えることができます。

サンプルプログラム

以下のコードは、リスト内の文字列から「郵便番号(3桁-4桁)」の形式に合致するものだけを抽出する例です。

import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class RegexPredicateSample {
public static void main(String[] args) {
// 郵便番号のパターン(先頭から末尾まで完全に一致する必要がある)
Pattern zipPattern = Pattern.compile(“\\d{3}-\\d{4}”);

List inputs = List.of(“123-4567”, “99-12345”, “000-1111”, “invalid”);

// asMatchPredicate()を使用してPredicateを生成
List validZips = inputs.stream()
.filter(zipPattern.asMatchPredicate()) // ここでフィルタリング
.collect(Collectors.toList());

// 結果を出力
System.out.println(“抽出された郵便番号: ” + validZips);
}
}

応用・注意点

1. 完全一致であることに注意
`asMatchPredicate()` は、内部で `Matcher.matches()` を呼び出します。これは「文字列全体」がマッチするかを判定するため、部分一致を期待する場合は注意が必要です。部分一致を行いたい場合は、正規表現の先頭と末尾に `.` を付与するか、別の手法を検討してください。

2. パフォーマンスへの影響
`asMatchPredicate()` は、内部的に `Matcher` インスタンスを生成して利用します。非常に大量のデータを高速に処理する必要がある場合、`Pattern` 自体のコンパイルコスト(`Pattern.compile()`)をループの外側で行うことは必須ですが、`Predicate` 化した後の実行速度は通常の `matches()` と同等です。

3. 名前付きグループとの組み合わせ
正規表現で名前付きグループ(`(?…)`)を使用している場合でも、`asMatchPredicate()` は問題なく機能します。ただし、`Predicate` として利用する場合は「一致するか否か」の真偽値しか取得できないため、グループ内の値を取り出したい場合は、従来通り `Matcher` インスタンスを直接操作する設計に留めるのが現場での判断基準となります。

コメント

タイトルとURLをコピーしました