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
和显式创buildMatcher
和Pattern
之间的性能应该是相同的。
编辑
正如已经在评论中指出的那样,性能差异是不存在的,对于从String
或Matcher
进行replaceAll
的单个调用来说是正确的,但是,如果需要执行多次调用replaceAll
,那么可以预期它对于保持一个编译的Pattern
,所以相对昂贵的正则expression式模式编译不必每次都执行。
String.replaceAll()
源代码:
public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); }
它必须先编译模式 – 如果要在短string上使用相同的模式多次运行它,如果重新使用一个已编译的模式,性能会更好。
主要区别在于,如果您坚持用于生成Matcher
的Pattern
,则可以避免每次使用时重新编译正则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::replaceAll
和String::replaceAll
之间的另一个区别也是编译自己的Pattern
一个原因。 当你自己编译一个Pattern
,有像标志这样的选项来修改应用正则expression式的方式。 例如:
Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE);
Matcher
将应用您在调用Matcher::replaceAll
时设置的所有标志。
还有其他的标志可以设置。 大多数情况下,我只想指出Pattern
和Matcher
API有很多选项,这是超越简单的String::replaceAll