String.replaceFirst性能与算法替换

时间:2013-04-24 06:45:15

标签: java

假设我想用“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);
}

2 个答案:

答案 0 :(得分:2)

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

如果您确定经常调用它并且意味着您花费的时间太长,那么您可能会考虑使用更复杂的编码。除非你已经测量了它产生的差异,否则我认为这只是猜测。在这种情况下,第二行可以是一个选项。

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

答案 1 :(得分:1)

我写了some code来测试性能。请使用适当的参数在您的盒子上运行它以进行测试。命令行接受从0到1的double,表示测试输入与插入"yyy"子串的比率。

方法

生成长度为50,100,500,1000等的

5000随机字符串插入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;
        }
    }
    
  4. 结果

    该程序在JVM 7,Windows 7上运行。这些数字是在微秒中处理1批5000个随机字符串的平均时间。

    插入子字符串"yyy"

    0%
           Length |      50        100        500        1000         5000
    --------------|-------------------------------------------------------
     replaceFirst |   17389      22718      74194      137285       629438
        substring |    4429       7246      13421       18069        78920
    StringBuilder |    4604       5615      11509       19093        79366
    

    25%插入子字符串"yyy"

           Length |      50        100        500        1000         5000
    --------------|-------------------------------------------------------
     replaceFirst |   18531      24959      78211      146956       692992
        substring |    5250       6764      18994       27959       113805
    StringBuilder |    5768       8609      23857       45789       205580
    

    插入子字符串"yyy"

    50%
           Length |      50        100        500        1000         5000
    --------------|-------------------------------------------------------
     replaceFirst |   19833      27648      90932      162558       760558
        substring |    6007       8848      21909       37415       154959
    StringBuilder |    7075      12095      37765       70038       327171
    

    75%插入子字符串"yyy"

           Length |      50        100        500        1000         5000
    --------------|-------------------------------------------------------
     replaceFirst |   20318      28387      95967      176051       845799
        substring |    6840       9940      27469       47218       198464
    StringBuilder |    8794      13272      50498       94644       470656
    

    插入子字符串"yyy"

    100%
           Length |      50        100        500        1000         5000
    --------------|-------------------------------------------------------
     replaceFirst |   22984      31302     103640      192179       892965
        substring |    7846      11494      37093       58544       258356
    StringBuilder |   11113      24499      66164      121784       592664
    

    结论

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

    当找到+子字符串且字符串很长时,将字符串与substringStringBuilder连接的方法比"yyy"快2倍。

    这里的用例非常本地化。虽然substring方法更快,但除非你进行密集的字符串处理,否则增益是微不足道的。