Pattern.matches()仅适用于一次性布尔匹配,无法获取分组、位置或连续查找;复杂匹配必须显式创建Matcher实例,因其维护状态并支持find()、group()等操作。
Java 的 Pattern 和 Matcher 不是“拿来就能用”的工具类,它们的协作机制决定了:直接调用 Pattern.matches() 看似简单,但真要复用、提取、分组或处理多轮匹配,必须显式创建 Matcher 实例——否则会反复编译正则、丢失状态、无法获取捕获组。
Pattern.matches() 做复杂匹配这个静态方法只适合一次性布尔判断,底层每次调用都重新编译正则、新建 Matcher、执行一次 find() 并丢弃结果。它不返回 Matcher,所以你拿不到分组内容、起始/结束位置

find() 多次。
Pattern.matches() 做不到(\d{4})-(\d{2})-(\d{2}) 这种括号?它不暴露 group(1)、group(2)
Pattern.compile() 后必须调用 matcher() 才能真正干活Pattern 是正则编译后的不可变对象,本身不持有匹配上下文;Matcher 才是绑定具体字符串、维护匹配状态(如上次 find() 位置)的运行时实例。一个 Pattern 可以生成多个 Matcher,但每个 Matcher 只属于一个输入字符串。
Pattern.compile("...") 一次,再对每个字符串调用 pattern.matcher(input)
Matcher,反复调用 find(),它会自动从上一次结束位置继续matcher.reset(newString) 或 matcher.reset() 回到开头find()、matches() 和 lookingAt() 的行为差异很关键这三个方法都返回 boolean,但语义完全不同,选错就匹配失败:
find():只要字符串中**存在子串**满足正则,就返回 true,且把指针移到匹配段末尾(支持循环调用)matches():要求**整个字符串**完全匹配正则(等价于在正则前后加 ^ 和 $),常被误用于子串场景lookingAt():只要字符串**开头部分**匹配正则(不要求全串),类似 ^ 开头但不强制结尾例如正则 "\\d+" 匹配字符串 "123abc":find() 成功,matches() 失败,lookingAt() 成功。
group() 的索引容易搞混group(0) 永远是整个匹配的字符串,不是第一个括号;真正的第一个捕获组是 group(1),以此类推。如果某组未参与本次匹配(比如用了 (a)? 但没匹配到 a),group(n) 返回 null,不是空字符串。
groupCount() 判断某组是否存在——它只返回正则里左括号数量,不管是否匹配成功if (matcher.group(2) != null) 再用"(?\\d{4})" ,取值用 matcher.group("year"),比数字索引更可读真正麻烦的从来不是写对正则,而是忘记 Matcher 是有状态的、以为 matches() 能替代 find()、或者在循环里反复 new Matcher 却没重置——这些细节不踩一遍坑,很难意识到它们才是性能和逻辑错误的源头。