String.replaceAll and StringUtils.replace (assuming Apache Commons here) are two completely different beasts. The former is using a Regular Expression as search term and performs a replacement with support of Regular Expressions as well, the latter is just looking for occurrences of the given text and replaces it by the replacement text.
With String.replaceAll you can e.g. do something like this:
System.out.println("John Smith".replaceAll("^(\S+)\s*(\S+)\*
2, $1"));
which will output
Smith, John
You can't do that with StringUtils.replace.
Assuming both libraries are available and we are not passing in a regex.
String.replaceAll is always parsing the search-term as Regex and performs the replacement assuming it to be using regex-functions as well, so it simply doesn't make sense to use this method without actually using Regex.
If you just want to do a simple text-replacement you just use String.replace(CharSequence c1, CharSequence c2) that was added with Java 1.5
From the few previous posts on this topic I see there are multiple tests and benchmarks pointing to that String.replace
Some sources would be nice, where you've seen that statement. The link Nexevis provided covered Java 1.4 where above method didn't exist and - without doing some tests myself now - I have doubts that the performance between String.replace(CharSequence...) and StringUtils.replace differ a lot because StringUtils' implementation looks quite straight forward and will most likely not differ a lot from the implementation in the JVM. The existence of it is purely historical because of the lack of a similar method in Java Version before 1.5
You don't need to escape the single quote in Strings (only in char values), and you need a double-double escape with the replacement value:
innerValue.replaceAll("'", "\\\\'")
This is due to replaceAll taking regular expressions as arguments (the second parameter must support regular expressions for back references).
You can also use the replace idiom, since you're not using regular expressions:
innerValue.replace("'", "\\'")
Note
The replace method actually uses replaceAll behind the scenes, but transforms values into literals by invoking Pattern.compile with the Pattern.LITERAL flag, and Matcher.quoteReplacement on the replacement.
Java String Package replaceAll method expects RegularExpression as String parameter. Whereas Commons Lang StringUtils.replace expects String value.
We have to do double escape when it comes to native Java implementation. System.out.println("replaceAll output:"+innerValue.replaceAll("'", "\\'"));
In modern Java, this is not the case anymore. String.replace was improved in Java-9 moving from regular expression to StringBuilder, and was improved even more in Java-13 moving to direct allocation of the target byte[] array calculating its exact size in advance. Thanks to internal JDK features used, like the ability to allocate an uninitialized array, ability to access String coder and ability to use private String constructor which avoids copying, it's unlikely that current implementation can be beaten by a third-party implementation.
Here are my benchmarking results for your test using JDK 8, JDK 9 and JDK 13 (caliper:0.5-rc1; commons-lang3:3.9)
Java 8 (4x slower indeed):
0% Scenario{vm=java, trial=0, benchmark=M1} 291.42 ns; σ=6.56 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=M2} 70.34 ns; σ=0.15 ns @ 3 trials
benchmark ns linear runtime
M1 291.4 ==============================
M2 70.3 =======
Java 9 (almost equal performance):
0% Scenario{vm=java, trial=0, benchmark=M2} 99,15 ns; σ=8,34 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=M1} 103,43 ns; σ=9,01 ns @ 10 trials
benchmark ns linear runtime
M2 99,1 ============================
M1 103,4 ==============================
Java 13 (standard method is 38% faster):
0% Scenario{vm=java, trial=0, benchmark=M2} 91,64 ns; σ=5,12 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=M1} 57,38 ns; σ=2,51 ns @ 10 trials
benchmark ns linear runtime
M2 91,6 ==============================
M1 57,4 ==================
From the source code of java.lang.String1:
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
The class was moved from package
org.apache.commons.
lang3
to
org.apache.commons.text
You can replace the deprecated library easily:
In your build.gradle:
implementation 'org.apache.commons:commons-text:1.11.0'
And in your class using StringEscapeUtils make sure you import the correct class:
import org.apache.commons.text.StringEscapeUtils;
1.11.0 is currently the newest version (last checked February 20th 2024) but you can check the versions at maven: https://mvnrepository.com/artifact/org.apache.commons/commons-text
Per the deprecation listing, it was moved to a new project -- commons-text