Back to Blog
Java

Java replace vs replaceAll: Literal Text vs Regex

java replace vs replaceall: Understand the difference between Java's replace() and replaceAll() methods, including regex behavior, replacement string escaping, and per...

Java StringRegexString ManipulationPattern MatchingJava Performance
An illustration of a Java string splitting into two paths, one for literal replacement and one for regex pattern matching

The difference between java replace vs replaceall comes down to one question: is the search term a literal string or a regular expression? Both methods replace every occurrence of a target in a String, but they interpret their first argument differently. replace() treats it as plain text; replaceAll() compiles it as a regex pattern. Choosing the wrong one produces incorrect output or unexpected exceptions.

How replace() Handles Literal Text

String input = "a.b.c.d"; String result = input.replace(".", "-"); // result: "a-b-c-d"

The dot is treated as a literal period. replace() scans the string and substitutes every occurrence of the exact character sequence. The method signature is replace(CharSequence target, CharSequence replacement), and neither argument is interpreted specially.

replace() also has a char overload: replace(char oldChar, char newChar). That overload has existed since Java 1.0, while the CharSequence version was added in Java 5. Both replace all occurrences, not just the first. There is no replaceFirst equivalent for literal text; that method exists only on Matcher.

When replaceAll() Requires a Regex

String input = "user1: 100, user2: 200"; String result = input.replaceAll("\\d+", "0"); // result: "user1: 0, user2: 0"

replaceAll(String regex, String replacement) compiles the first argument as a regular expression. The pattern \\d+ matches one or more digits. This is the fundamental behavioral difference: any regex metacharacter in the search term is interpreted by the pattern engine.

That means replaceAll(".") does not replace literal dots. The dot matches any single character, so every character in the string is a match:

String input = "a.b.c"; String result = input.replaceAll(".", "-"); // result: "---"

To replace literal dots, the pattern must be escaped: replaceAll("\\.", "-"). This is the most common source of confusion between the two methods.

The Replacement String: A Hidden Difference

The replacement argument behaves differently in the two methods. With replace(), the replacement is inserted verbatim. With replaceAll(), the replacement is processed by Matcher.replaceAll(), which interprets backslashes and dollar signs.

String input = "John Smith"; String result = input.replaceAll("(\\w+) (\\w+)", "$2, $1"); // result: "Smith, John"

$1 and $2 reference the two capturing groups. To insert a literal dollar sign in the output, it must be escaped in the replacement string:

String input = "total: 100"; String result = input.replaceAll("100", "\\$100"); // result: "total: $100"

The same operation with replace() needs no escaping at all:

String result = input.replace("100", "$100"); // result: "total: $100"

If the replacement comes from user input or configuration and must be inserted literally while the search pattern is a regex, wrap it with Matcher.quoteReplacement():

String literal = Matcher.quoteReplacement(userProvidedReplacement); String result = input.replaceAll(pattern, literal);

Performance: Regex Compilation and Allocation

Every call to replaceAll() compiles the regex pattern internally through Pattern.compile(regex). That involves parsing the pattern, building the internal matcher state, and allocating objects. replace() performs a simple character scan using indexOf internally, with no pattern parsing.

For a one-off operation, the difference is usually negligible. But in a loop over many strings, repeated compilation cost accumulates:

for (String line : lines) { String cleaned = line.replaceAll("\\s+", " "); // Pattern.compile("\\s+") runs on every iteration }

When the same pattern is applied repeatedly, compile it once and reuse it:

Pattern whitespace = Pattern.compile("\\s+"); for (String line : lines) { String cleaned = whitespace.matcher(line).replaceAll(" "); }

The Pattern is immutable and thread-safe, so it can be stored in a static field and shared across threads. The Matcher is created per call and is not thread-safe, but since it is used locally, that is not a problem. For purely literal replacements, replace() is the better choice: it avoids regex compilation entirely and makes the code's intent obvious.

Common Mistakes and Edge Cases

The most frequent mistake is passing a literal string that contains regex metacharacters to replaceAll(). File paths, URLs, and currency amounts are common culprits.

String path = "C:\\Users\\admin"; String result = path.replaceAll("\\", "/");

This throws PatternSyntaxException because a single backslash is an incomplete escape in regex syntax. The correct literal replacement is:

String result = path.replace("\\", "/");

Another edge case is the replacement string containing $ or \ when using replaceAll(). A currency value like $5 in the replacement is interpreted as a group reference, and referencing a group that does not exist throws IndexOutOfBoundsException. If the replacement is not under your control, always pass it through Matcher.quoteReplacement().

Choosing Between replace() and replaceAll()

The decision rule is based on what the search term actually is:

ConditionMethod
Search term is plain text with no regex metacharactersreplace()
Search term must be interpreted as a regex patternreplaceAll()
Replacement contains $ or \ and must be inserted literallyreplace()
Search is a regex and replacement must be literalreplaceAll() with Matcher.quoteReplacement()
Same regex applied to many stringsPre-compiled Pattern with matcher().replaceAll()

Use replace() whenever the target is a literal string. It is faster, clearer, and avoids escaping bugs. Use replaceAll() only when the first argument genuinely needs to be a regular expression.

If a dynamic search string comes from user input but must be treated literally, wrap it with Pattern.quote():

String literalPattern = Pattern.quote(userInput); String result = input.replaceAll(literalPattern, replacement);

Pattern.quote() escapes every metacharacter so the regex engine treats the input as literal text.

Reusing a Compiled Pattern for Repeated Replacements

When the same regex is applied across many strings, pre-compiling the Pattern is both the efficient and the maintainable approach.

private static final Pattern WHITESPACE = Pattern.compile("\\s+"); public String normalize(String text) { return WHITESPACE.matcher(text).replaceAll(" "); }

Storing the compiled pattern in a static final field ensures it is compiled once per class load. The Matcher is still allocated per call, but the expensive pattern parsing happens only once.

This approach also composes cleanly with quoteReplacement when the replacement contains characters that would otherwise be interpreted:

String replacement = Matcher.quoteReplacement("$2.50"); String result = WHITESPACE.matcher(input).replaceAll(replacement);

The combination of a pre-compiled Pattern and a quoted replacement gives you regex search power with literal replacement safety, without paying the compilation cost on every call.

java replace vs replaceall: Practical Usage and Code Example | RYUSLOG DEV