String replaceAll()与Matcher replaceAll()(性能差异)

很简单的问题,但是这是来自一个C / C ++人进入Java的错综复杂。

我知道我可以启动jUnit和我自己的一些性能testing来获得答案; 但我只是想知道这是否在那里。

在性能方面,String.replaceAll()和Matcher.replaceAll()(从Regex.Pattern创build的Matcher对象)之间是否存在已知的区别?

另外,两者之间高级API的区别是什么? (不变性,处理NULL,处理空串,制作咖啡等)

根据String.replaceAll的文档,关于调用方法有以下几点:

str.replaceAll(regex, repl)forms的此方法的调用产生与expression式完全相同的结果

 Pattern.compile(regex).matcher(str).replaceAll(repl) 

因此,可以预期调用String.replaceAll和显式创buildMatcherPattern之间的性能应该是相同的。

编辑

正如已经在评论中指出的那样,性能差异是不存在的,对于从StringMatcher进行replaceAll的单个调用来说是正确的,但是,如果需要执行多次调用replaceAll ,那么可以预期它对于保持一个编译的Pattern ,所以相对昂贵的正则expression式模式编译不必每次都执行。

String.replaceAll()源代码:

 public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } 

它必须先编译模式 – 如果要在短string上使用相同的模式多次运行它,如果重新使用一个已编译的模式,性能会更好。

主要区别在于,如果您坚持用于生成MatcherPattern ,则可以避免每次使用时重新编译正则expression式。 通过String ,你不能像这样“caching”。

如果每次都有不同的正则expression式,那么使用String类的replaceAll就可以了。 如果您对多个string应用相同的正则expression式,请创build一个Pattern用它。

不变性/线程安全性:编译模式是不可变的,匹配器不是。 (请参阅Java正则expression式线程安全?

处理空string:replaceAll应该优雅地处理空string(它不会匹配一个空的inputstring模式)

制作咖啡等:最后我听说,无论是string,模式或匹配器都没有APIfunction。

编辑:至于处理空值,string和模式的文档没有明确地说,但我怀疑他们会抛出一个NullPointerException,因为他们期望一个string。

String.replaceAll的实现告诉你你需要知道的一切:

 return Pattern.compile(regex).matcher(this).replaceAll(replacement); 

(文档也是一样的)

虽然我没有检查过caching,但我肯定希望编译一次模式并保持一个静态引用,这比每次调用具有相同模式的Pattern.compile效率更高。 如果有一个caching,这将是一个小的效率节约 – 如果没有它可能是一个大的。

不同的是,String.replaceAll()每次调用时都会编译正则expression式。 .NET的静态Regex.Replace()方法没有相应的function,它会自动caching编译后的正则expression式。 通常,replaceAll()是你只做过一次的事情,但是如果你打算用相同的正则expression式重复地调用它,特别是在循环中,你应该创build一个Pattern对象并使用Matcher方法。

您也可以提前创build匹配器,并使用它的reset()方法为每次使用重新对其进行重定位:

 Matcher m = Pattern.compile(regex).matcher(""); for (String s : targets) { System.out.println(m.reset(s).replaceAll(repl)); } 

重复使用匹配器的性能好处当然不如重用模式那么好。

其他答案充分覆盖了OP的性能部分,但Matcher::replaceAllString::replaceAll之间的另一个区别也是编译自己的Pattern一个原因。 当你自己编译一个Pattern ,有像标志这样的选项来修改应用正则expression式的方式。 例如:

 Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE); 

Matcher将应用您在调用Matcher::replaceAll时设置的所有标志。

还有其他的标志可以设置。 大多数情况下,我只想指出PatternMatcher API有很多选项,这是超越简单的String::replaceAll