String.replace实现真的很有效吗?

时间:2013-01-25 08:25:10

标签: java

我曾经认为String.replace比String.replaceAll更快,因为后者使用Pattern正则表达式而前者不使用。但事实上,在性能或实施方面没有显着差异。就是这样:

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

这里有什么需要使用Pattern?我写了一个非正则表达式替换版本

static String replace(String s, String target, String replacement) {
    StringBuilder sb = new StringBuilder(s);
    for (int i = 0; (i = sb.indexOf(target, i)) != -1; i += replacement.length()) {
        sb.replace(i, i + target.length(), replacement);
    }
    return sb.toString();
}

并比较表现

    public static void main(String args[]) throws Exception {
        String s1 = "11112233211";
        for (;;) {
            long t0 = System.currentTimeMillis();
            for (int i = 0; i < 1000000; i++) {
//              String s2 = s1.replace("11", "xxx");
                 String s2 = replace(s1, "11", "22");
            }
            System.out.println(System.currentTimeMillis() - t0);
        }
    }

基准:我的版本 - 400ms; JDK版本 - 1700ms

我的测试是错误的还是String.replace真的效率不高?

3 个答案:

答案 0 :(得分:11)

让你知道String.replace是多么低效

来自Java 7更新11的源代码。

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

AFAIK,使用Pattern和Matcher.quiteReplacement等是一种明确而非有效的尝试。我怀疑它可以追溯到许多内部库是在没有性能考虑的情况下编写的。

恕我直言Java 7已经看到许多内部库提高了性能,特别是减少了不必要的对象创建。这种方法显然是一种改进的选择。


您可以通过执行一次复制来提高性能,而不是尝试插入现有的StringBuilder。

static String replace2(String s, String target, String replacement) {
    StringBuilder sb = null;
    int start = 0;
    for (int i; (i = s.indexOf(target, start)) != -1; ) {
        if (sb == null) sb = new StringBuilder();
        sb.append(s, start, i);
        sb.append(replacement);
        start = i + target.length();
    }
    if (sb == null) return s;
    sb.append(s, start, s.length());
    return sb.toString();
}

public static void main(String... ignored) {
    String s1 = "11112233211";
    for (; ; ) {
        timeReplace(s1);
        timeReplace2(s1);
        timeStringReplaceRefactored(s1);
        timeStringReplace(s1);
    }
}

private static void timeStringReplace(String s1) {
    long start0 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s2 = s1.replace("11", "xxx");
        if (s2.length() <= s1.length()) throw new AssertionError();
    }
    System.out.printf("String.replace %,d ns avg%n", System.currentTimeMillis() - start0);
}

private static void timeStringReplaceRefactored(String s1) {
    long start0 = System.currentTimeMillis();
    Pattern compile = Pattern.compile("11", Pattern.LITERAL);
    String xxx = Matcher.quoteReplacement("xxx");
    for (int i = 0; i < 1000000; i++) {
        String s2 = compile.matcher(s1).replaceAll(xxx);
        if (s2.length() <= s1.length()) throw new AssertionError();
    }
    System.out.printf("String.replace %,d ns avg (Refactored)%n", System.currentTimeMillis() - start0);
}
private static void timeReplace(String s1) {
    long start0 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s2 = replace(s1, "11", "xxx");
        if (s2.length() <= s1.length()) throw new AssertionError();
    }
    System.out.printf("Replace %,d ns avg%n", System.currentTimeMillis() - start0);
}

private static void timeReplace2(String s1) {
    long start0 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s2 = replace2(s1, "11", "xxx");
        if (s2.length() <= s1.length()) throw new AssertionError();
    }
    System.out.printf("My replace %,d ns avg%n", System.currentTimeMillis() - start0);
}

static String replace(String s, String target, String replacement) {
    StringBuilder sb = new StringBuilder(s);
    for (int i = 0; (i = sb.indexOf(target, i)) != -1; i += replacement.length()) {
        sb.replace(i, i + target.length(), replacement);
    }
    return sb.toString();
}

打印

Replace 177 ns avg
My replace 108 ns avg
String.replace 436 ns avg (Refactored)
String.replace 598 ns avg

捕捉模式并替换文本有一点帮助,但不如使用自定义例程进行替换。

答案 1 :(得分:1)

比较两种解决方案时有一个有趣的方面,至少在我的机器上。当涉及到更大的字符串时,内置版本可以更好地扩展。给出一个稍微修改过的测试版本:

for (int i = 0; i < 10; i++) {
    s1 = s1 + s1;
    long t0 = call1(s1); // your implementation
    long t1 = call2(s1); // 1.7_07 Oracle
    long delta = t0 - t1;

    System.out.println(
      String.format("Iteration %s, string length %s, call1 %s, call2 %s, delta %s", i, s1.length(), t0, t1, delta));

    try {
        Thread.sleep(200);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

通过在每次调用时将字符串长度加倍,在迭代3或4之后已达到收支平衡:

Iteration 0, string length 22, call1 450, call2 1715, delta -1265
Iteration 1, string length 44, call1 1048, call2 2152, delta -1104
Iteration 2, string length 88, call1 2695, call2 4024, delta -1329
Iteration 3, string length 176, call1 7737, call2 7574, delta 163
Iteration 4, string length 352, call1 24662, call2 15560, delta 9102

参考call1和call2的两个实现:

static long call1(String s) {
    long t0 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s2 = replace(s, "11", "22");
    }
    return System.currentTimeMillis() - t0;
}

static long call2(String s) {
    long t0 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s2 = s.replace("11", "xxx");
    }
    return System.currentTimeMillis() - t0;
}

答案 2 :(得分:0)

字符串替换和替换所有方法没有效率或时间的差异都采取n操作来替换charecter下面的代码可能会帮助你如何在java中使用字符串替换方法工作你可以在你的日食中结帐

package com.jav.exec;

public class replace {

    static String s1="This the India the india the nation";

    public static String replace(String s2,String s3)
    {
        int counter=0;
        int count=s3.length()-1;
        int count1=0;
        char[] ca1=s1.toCharArray();
        char[] ca2=s2.toCharArray();
        char[] ca3=s3.toCharArray();

        for(int f1=0;f1<ca1.length;f1++)//finding the number of occurances
        {
            if(ca1[f1]==ca2[counter])//increasing counter if charecters matches
            {
                counter++;

                if(counter==s2.length())//if consecutive charecters makes count equal to replacing string
                {
                    count1++;//increasing the count if consecutive charecters matches the striing
                    counter=0;//making counter 0 for next occurence
                }
            }
            else
            {
                counter=0;//making counter 0 if occurence less than the string 
            }
        }

        char[] ca4=new char[ca1.length+(count1*ca3.length)-(count1*ca2.length)];
        //creating new sized array for storing values
        counter=0;
        count=s3.length()-1;
        count1=0;
        int count2=0;

        for(int f=0;f<ca4.length;f++)
        {
            ca4[f]=ca1[count2];//storing the values into the new array of original long array
            //increasing the count  
            if(ca1[count2]==ca2[counter])//if charecters matches replacing array charecters
            {
                counter++;
                if(counter==ca2.length)//if counter is equal to length of replacing array
                {
                    f=f+ca3.length-ca2.length;//increasing the count of f
                    for(int f1=0;f1<ca3.length;f1++)//storing replaced array charecters to new array
                    {
                        ca4[f-count]=ca3[count1];
                        count1++;
                        count--;
                    }
                    counter=0;//redeclaring variables to their inital values for next replacement
                    count1=0;
                    count=s3.length()-1;
                }
            }

            else
            {   
                while(counter>0)
                {   
                    ca4[f-counter]=ca1[count2-counter];
                    counter--;
                }
            }
            count2++;
        }
        return new String(ca4);
    }

    public static void main(String[] args)
    {
        System.out.println(replace("the","mother"));
    }
}