Is String.replace implementation really efficient?

后端 未结 3 898
青春惊慌失措
青春惊慌失措 2021-02-13 03:55

I used to think that String.replace is faster than String.replaceAll because the latter uses Pattern regex and the former does not. But in fact there is no significant differenc

3条回答
  •  猫巷女王i
    2021-02-13 04:37

    To give you some idea how inefficient String.replace is

    From the source for Java 7 update 11.

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

    AFAIK, the use of a Pattern and Matcher.quiteReplacement etc is an attempt to be clear rather than efficient. I suspect it dates back to when many internal libraries were written without performance considerations.

    IMHO Java 7 has seen many internal libraries improve performance, in particular reduce needless object creation. This method is an obvious candidate for improvement.


    You can improve the performance by doing the copy once, instead of trying to insert into an existing 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();
    }
    

    prints

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

    Catching the Pattern and replace text helps a little, but not as much as having a custom routine to do the replace.

提交回复
热议问题