compile() 方法总是在某个时候被调用;这是创建 Pattern 对象的唯一方法。所以问题是,为什么要明确地称它为?一个原因是您需要对 Matcher 对象的引用,以便您可以使用它的方法,例如 group(int) 来检索捕获组的内容。获取 Matcher 对象的唯一方法是通过 Pattern 对象的 matcher() 方法,而获取 Pattern 对象的唯一方法是通过 compile() 方法。然后是find() 方法,与matches() 不同,它不会在String 或Pattern 类中重复。
另一个原因是避免一遍又一遍地创建相同的 Pattern 对象。每次使用 String 中的正则表达式驱动方法之一(或 Pattern 中的静态 matches() 方法)时,它都会创建一个新 Pattern 和一个新 Matcher。所以这段代码sn-p:
for (String s : myStringList) {
if ( s.matches("\\d+") ) {
doSomething();
}
}
...完全等价于:
for (String s : myStringList) {
if ( Pattern.compile("\\d+").matcher(s).matches() ) {
doSomething();
}
}
显然,这做了很多不必要的工作。事实上,与执行实际匹配相比,编译正则表达式和实例化 Pattern 对象很容易花费更长的时间。因此,将这一步拉出循环通常是有意义的。您也可以提前创建 Matcher,尽管它们的成本并不高:
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("");
for (String s : myStringList) {
if ( m.reset(s).matches() ) {
doSomething();
}
}
如果您熟悉 .NET 正则表达式,您可能想知道 Java 的 compile() 方法是否与 .NET 的 RegexOptions.Compiled 修饰符有关;答案是不。 Java 的Pattern.compile() 方法仅相当于.NET 的Regex 构造函数。当您指定 Compiled 选项时:
Regex r = new Regex(@"\d+", RegexOptions.Compiled);
...它将正则表达式直接编译为 CIL 字节码,使其执行速度更快,但在前期处理和内存使用方面付出了巨大的代价——将其视为正则表达式的类固醇。 Java 没有等价物;由String#matches(String) 在幕后创建的模式与您使用Pattern#compile(String) 显式创建的模式之间没有区别。
(编辑:我最初说所有 .NET Regex 对象都被缓存,这是不正确的。从 .NET 2.0 开始,自动缓存仅发生在 Regex.Matches() 之类的静态方法中,而不是在您直接调用 Regex 构造函数时发生。@987654321 @)