Commons Lang StringUtils.replace performance vs String.replace

java

Solution

From the source code of `java.lang.String`1:

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

`String.replace(CharSequence target, CharSequence replacement)` is implemented with `java.util.regex.Pattern`, therefore, it is not surprising that it is slower that `StringUtils.replace(String text, String searchString, String replacement)`2, which is implemented with `indexOf` and `StringBuffer`.

public static String replace(String text, String searchString, String replacement) {
    return replace(text, searchString, replacement, -1);
}

public static String replace(String text, String searchString, String replacement, int max) {
    if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
        return text;
    }
    int start = 0;
    int end = text.indexOf(searchString, start);
    if (end == -1) {
        return text;
    }
    int replLength = searchString.length();
    int increase = replacement.length() - replLength;
    increase = (increase < 0 ? 0 : increase);
    increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
    StringBuffer buf = new StringBuffer(text.length() + increase);
    while (end != -1) {
        buf.append(text.substring(start, end)).append(replacement);
        start = end + replLength;
        if (--max == 0) {
            break;
        }
        end = text.indexOf(searchString, start);
    }
    buf.append(text.substring(start));
    return buf.toString();
}

Footnote

1 The version that I links to and copied source code from is JDK 7

2 The version that I links to and copied source code from is common-lang-2.5

Problem

When I compared performance of Apache's `StringUtils.replace()` vs `String.replace()` I was surprised to know that the former is about 4 times faster. I used Google's Caliper framework to measure performance. Here's my test ``` public class Performance extends SimpleBenchmark { String s = "111222111222"; public int timeM1(int n) { int res = 0; for (int x = 0; x < n; x++) { res += s.replace("111", "333").length(); } return res; } public int timeM2(int n) { int res = 0; for (int x = 0; x < n; x++) { res += StringUtils.replace(s, "111", "333", -1).length(); } return res; } public static void main(String... args) { Runner.main(Performance.class, args); } } ``` output ``` 0% Scenario{vm=java, trial=0, benchmark=M1} 9820,93 ns; ?=1053,91 ns @ 10 trials 50% Scenario{vm=java, trial=0, benchmark=M2} 2594,67 ns; ?=58,12 ns @ 10 trials benchmark us linear runtime M1 9,82 ============================== M2 2,59 ======= ``` Why is that? Both methods seem to do the same work, `StringUtils.replace()` is even more flexible.

Original source

Related problems