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.