String.replaceAll 比自己做这项工作要慢得多

2022-09-01 06:30:47

我有一段旧代码,可以执行字符串中令牌的查找和替换。

它接收 和 对的映射,迭代它们,并针对其中每个对,迭代目标字符串,查找 using ,并将其替换为 的值。它完成 上的所有工作,并最终返回 .fromtofromindexOf()toStringBufferString

我用这行替换了该代码:
并且我运行了一些比较性能测试。
在比较迭代时,我得到了这个:replaceAll("[,. ]*", "");1,000,000

旧代码: 1287ms
新代码: 4605ms

3倍以上!

然后,我尝试将其替换为3个调用:replace
replace(",", "");
replace(".", "");
replace(" ", "");

这导致了以下结果:

旧代码: 1295
新代码: 3524

2倍以上!

任何想法为什么和效率如此低?我可以做些什么来让它更快吗?replacereplaceAll


编辑:感谢所有的答案 - 主要问题确实是没有做我想要它做的事情。将其更改为几乎等于非基于正则表达式的解决方案的性能。使用预编译的正则表达式有所帮助,但微不足道。(这是一个非常适用于我的问题的解决方案。[,. ]*[,. ]+

测试代码:
将字符串替换为正则表达式: [,. ]*
将字符串替换为正则表达式:[,. ]+
将字符串替换为正则表达式:[,. ]+ 和预编译模式


答案 1

虽然使用正则表达式会带来一些性能影响,但它不应该那么可怕。

请注意,使用 String.replaceAll() 将在每次调用正则表达式时编译正则表达式。

您可以通过显式使用 Pattern 对象来避免这种情况:

Pattern p = Pattern.compile("[,. ]+");

// repeat only the following part:
String output = p.matcher(input).replaceAll("");

另请注意,使用代替可以避免替换空字符串,因此也可能加快该过程。+*


答案 2

replace并在内部使用正则表达式,在大多数情况下,与StringUtils.replace(..)相比,这会产生严重的性能影响replaceAll

String.replaceAll()

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

String.replace() 在下面使用 Pattern.compile。

public String replace(CharSequence target, CharSequence replacement) {
  return Pattern.compile(target.toString(), Pattern.LITERAL)
         .matcher(this ).replaceAll(
           Matcher.quoteReplacement(replacement.toString()));
}

另请参阅替换字符串中出现的所有子字符串 - 这在 Java 中更有效?