非常简单的问题,但这是来自C / C ++人员进入Java的复杂性。
我知道我可以启动jUnit和我自己的一些性能测试来得到答案;但我只是想知道这是否在那里。
在性能方面,String.replaceAll()和Matcher.replaceAll()(从Regex.Pattern创建的Matcher对象)之间是否存在已知差异?
此外,两者之间的高级API是什么区别? (不变性,处理空白,处理空字符串,制作咖啡等)。
答案 0 :(得分:73)
根据String.replaceAll
的文档,它有关于调用方法的以下内容:
调用此方法 表格
str.replaceAll(regex, repl)
产生与结果完全相同的结果 表达Pattern.compile(regex).matcher(str).replaceAll(repl)
因此,可以预期调用String.replaceAll
和明确创建Matcher
和Pattern
之间的性能应该相同。
修改强>
正如评论中指出的那样,对replaceAll
或String
的{{1}}的单次调用,性能差异不存在,但是,如果需要的话要对Matcher
执行多次调用,人们会认为保持编译的replaceAll
是有益的,因此不必每次都执行相对昂贵的正则表达式模式编译。
答案 1 :(得分:23)
String.replaceAll()
的源代码:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
首先要编译模式 - 如果要在短字符串上使用相同的模式多次运行它,如果重用一个已编译的模式,性能会好得多。
答案 2 :(得分:9)
主要区别在于,如果你抓住用于生成Pattern
的{{1}},就可以避免每次使用它时重新编译正则表达式。通过Matcher
,您无法像这样“缓存”。
如果每次使用不同的正则表达式,使用String
类的String
都可以。如果要将相同的正则表达式应用于多个字符串,请创建一个replaceAll
并重复使用它。
答案 3 :(得分:6)
不变性/线程安全性:编译模式是不可变的,匹配器不是。 (见Is Java Regex Thread Safe?)
处理空字符串:replaceAll应该优雅地处理空字符串(它与空输入字符串模式不匹配)
制作咖啡等:最后我听说,String和Pattern以及Matcher都没有任何API功能。
编辑:至于处理NULL,String和Pattern的文档没有明确说明,但我怀疑他们会抛出一个NullPointerException,因为他们期望一个String。
答案 4 :(得分:4)
String.replaceAll
的实施告诉您需要知道的一切:
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
(文档说同样的话。)
虽然我没有检查过缓存,但我当然希望编译模式一次并保持静态引用比使用相同的方法调用Pattern.compile
更有效每次模式。如果有一个缓存,它将是一个小的效率节省 - 如果没有它可能是一个大的。
答案 5 :(得分:4)
不同之处在于String.replaceAll()每次调用时都会编译正则表达式。 .NET的静态Regex.Replace()方法没有等价物,它自动缓存已编译的正则表达式。通常,replaceAll()只能执行一次,但如果您要使用相同的正则表达式重复调用它,尤其是在循环中,则应创建一个Pattern对象并使用Matcher方法。
您也可以提前创建Matcher,并使用其reset()方法为每次使用重新定位:
Matcher m = Pattern.compile(regex).matcher("");
for (String s : targets)
{
System.out.println(m.reset(s).replaceAll(repl));
}
当然,重用Matcher的性能优势远不如重用模式那么好。
答案 6 :(得分:0)
其他答案足以涵盖OP的性能部分,但Matcher::replaceAll
和String::replaceAll
之间的另一个差异也是编译自己的Pattern
的原因。当您自己编译Pattern
时,有一些选项,如标志,用于修改正则表达式的应用方式。例如:
Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE);
Matcher
将应用您拨打Matcher::replaceAll
时设置的所有标记。
您还可以设置其他标志。大多数情况下,我只想指出Pattern
和Matcher
API有很多选项,这是超越简单String::replaceAll