2

假设我想用“zzz”替换字符串中第一次出现的“yyy”。String.replaceFirst 似乎是一个完美的解决方案

str = str.repaceFirst("yyy", "zzz");

但是有性能问题吗?以下解决方案在性能方面有什么不同吗?

int i = s.indexOf("yyy");
if (i != -1) {
    str = str.substring(0, i) + "zzz" + s.substring(i + 3);
}
4

2 回答 2

4

我写了一些代码来测试性能。请使用适当的参数在您的盒子上运行它来测试它。命令行接受一个double从 0 到 1 的值,表示测试输入与插入"yyy"子字符串的比率。

方法

生成5000个长度为50、100、500、1000等的随机字符串5000 个字符串中的一部分在随机位置插入序列“yyy” 。(由于生成方法,字符串将只包含一个实例,"yyy"如果有的话,但我认为这不是问题)。对于(字符串长度)和(方法)的每种组合,我运行测试30次并取平均值。

测试了以下 3 种方法:

  1. replaceFirst

    public static String replaceFirstApproach(String input) {
        return input.replaceFirst("yyy", "zzz");
    }
    
  2. substring

    public static String substringApproach(String input) {
        int i = input.indexOf("yyy");
    
        if (i != -1) {
            input = input.substring(0, i) + "zzz" + input.substring(i + 3);
        }
    
        return input;
    }
    
  3. 用于StringBuilder构造输出字符串:

    public static String appendStringBuilder(String input) {
        int i = input.indexOf("yyy");
    
        if (i != -1) {
            StringBuilder output = new StringBuilder(input.length());
            output.append(input, 0, i).append("zzz").append(input, i + 3, input.length());
            return output.toString();
        } else {
            return input;
        }
    }
    

结果

该程序在 JVM 7、Windows 7 上运行。这些数字是处理 1 批 5000 个随机字符串的平均时间(以微秒为单位)。

在插入子字符串的0%处"yyy"

       长度 | 50 100 500 1000 5000
--------------|------------------------------------ --------------------
 替换优先 | 17389 22718 74194 137285 629438
    子串 | 4429 7246 13421 18069 78920
字符串生成器 | 4604 5615 11509 19093 79366

插入子字符串的25%"yyy"

       长度 | 50 100 500 1000 5000
--------------|------------------------------------ --------------------
 替换优先 | 18531 24959 78211 146956 692992
    子串 | 5250 6764 18994 27959 113805
字符串生成器 | 5768 8609 23857 45789 205580

插入子字符串的50%"yyy"

       长度 | 50 100 500 1000 5000
--------------|------------------------------------ --------------------
 替换优先 | 19833 27648 90932 162558 760558
    子串 | 6007 8848 21909 37415 154959
字符串生成器 | 7075 12095 37765 70038 327171

插入子字符串的75%"yyy"

       长度 | 50 100 500 1000 5000
--------------|------------------------------------ --------------------
 替换优先 | 20318 28387 95967 176051 845799
    子串 | 6840 9940 27469 47218 198464
字符串生成器 | 8794 13272 50498 94644 470656

插入子字符串的100%"yyy"

       长度 | 50 100 500 1000 5000
--------------|------------------------------------ --------------------
 替换优先 | 22984 31302 103640 192179 892965
    子串 | 7846 11494 37093 58544 258356
字符串生成器 | 11113 24499 66164 121784 592664

结论

的方法replaceFirst总是最慢的。当"yyy"未找到子字符串时,它比其他 2 种方法慢 3-10 倍。当"yyy"可以找到子字符串时,它仍然比substring接近慢 3 倍,StringBuilder接近 1.5 倍。

+使用and连接字符串的方法比可以找到子字符串且字符串很长时substring快 2 倍。StringBuilder"yyy"

不过,这里的用例非常本地化。尽管该substring方法更快,但除非您进行密集的字符串处理,否则收益微不足道。

于 2013-04-24T09:50:35.297 回答
2

通常最重要的是编写清晰简单的代码。就您的性能和必须维护代码的人而言,第一个选项是最好的。

如果您确定这被调用的频率足够高并且意味着您花费的时间太长,那么您可能会考虑使用更复杂的编码。除非你测量过它有多大的不同,否则我认为这只是一个猜测。在这种情况下,第二行可能是一个选项。

顺便说一句,可能有更快的方法,例如使用 StringBuilder 而不是根据您的上下文创建 String 。

于 2013-04-24T06:56:51.477 回答