本文介绍了String.replace实现真的很有效吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 difference either in performance or implementation. This is it:

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

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

What's the need to use Pattern here? I wrote a non-regex replace version

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

Benchmarks: my version - 400ms; JDK version - 1700ms.

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

Is my test wrong or is String.replace really inefficient?

推荐答案

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

To give you some idea how inefficient String.replace is

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

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,使用Pattern和Matcher.quiteReplacement等是尝试要清楚而不是有效。我怀疑它可以追溯到许多内部库是在没有性能考虑的情况下编写的。

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.

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

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

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

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();
}

打印

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.

这篇关于String.replace实现真的很有效吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 08:50