マッチしてるはずなのにIllegalStateException thrown: No match found
たとえば、ある文字列が「画面ID + 定型文字列」であるとして、ここから画面IDを抜き取るという実装を正規表現で行う場合…
jshellで実行してみると
まずは文字列の定義をします。この場合は"Bean"が定型文字列です。
jshell> String actionBeanName = "ScreenIdBean";
actionBeanName ==> "ScreenIdBean"
次に正規表現を定義します。任意の文字列で始まり1文字以上、そして後ろにBeanというパターンです。
jshell> Pattern p = Pattern.compile("^(.+)(Bean)$");
p ==> ^(.+)(Bean)$
matcherメソッドでMatchesオブジェクトを取得しgroup(1)を呼ぶと…なんとエラー!
jshell> p.matcher(actionBeanName).group(1) | java.lang.IllegalStateException thrown: No match found | at Matcher.group (Matcher.java:645) | at Matcher.group (Matcher.java:604) | at (#4:1)
確認のためにmatches()を呼ぶもtrue…
jshell> p.matcher(actionBeanName).matches()
$5 ==> true
再度group()を取っても同じくNo match foundエラーです。
一致しているはずなのに取れない理由は…
Matcherのmatches()を呼んだあと、そのオブジェクトでgroupを呼ぶ必要があります。
つまり下記のように、まずmを変数に代入して
jshell> java.util.regex.Matcher m = p.matcher(actionBeanName); m ==> java.util.regex.Matcher[pattern=^(.+)(Bean)$ region=0,12 lastmatch=]
そのオブジェクトmのmatches()を呼んだ後に
jshell> m.matches()
$7 ==> true
groupを呼ぶと、目的の文字列が抽出できました。
jshell> m.group(1)
$8 ==> "ScreenId"
groupを呼ぶには、一旦matches()を呼ばないといけない
正規表現が必ず一致すると明確な場合、エラーチェックとなるmatches()を省略しがちですが、ここが落とし穴でした。
本来であれば下記のように安全な(?)コーディングを行うので、起こりえないです。
String actionBeanName = "ScreenIdBean";
Matcher m = PATTERN.matcher(actionBeanName);
if (m.matches()) {
String screenId = m.group(1);
// 何かしらの処理.
} else {
// マッチしなかった場合の処理.
}
と、必ずエラーチェックしてたから今まで知らなかったと言い訳しておきます^^;