Back to Blog
Java

Java String replace: Literal Replacement Without Regex

java string replace: How Java's String.replace() works, how it differs from replaceAll() and replaceFirst(), and when to choose literal replacement over regex.

JavaStringreplaceregeximmutability
A Java String being transformed by the replace method, showing literal text substitution without regular expression pattern matching.

Java's String.replace() method replaces every occurrence of a literal character or text sequence in a string. It is the method developers reach for when they need straightforward text substitution without regular expression semantics. Understanding how java string replace behaves — and where it differs from replaceAll() and replaceFirst() — prevents a common class of bugs in text processing code.

String original = "banana"; String result = original.replace('a', 'o'); System.out.println(result); // "bonono"

The Two Overloads of String.replace()

The first overload takes two char arguments:

public String replace(char oldChar, char newChar)

Every occurrence of oldChar is replaced with newChar. The operation is a direct character-for-character substitution with no pattern matching involved.

The second overload takes two CharSequence arguments:

public String replace(CharSequence target, CharSequence replacement)

Every occurrence of target is replaced with replacement. Both arguments are treated as literal text, never as regular expressions. This is the critical distinction that causes most confusion when developers move between replace() and replaceAll().

String text = "The quick brown fox"; String result = text.replace("quick", "slow"); System.out.println(result); // "The slow brown fox"

The CharSequence overload accepts String, StringBuilder, StringBuffer, and any other implementation of CharSequence. In practice, String arguments are the most common.

How replace() Differs from replaceAll() and replaceFirst()

replaceAll() and replaceFirst() both interpret their first argument as a regular expression. replace() does not.

String text = "price: 100, discount: 20"; String withRegex = text.replaceAll("\\d+", "0"); String withLiteral = text.replace("\\d+", "0");

The first call replaces every digit sequence with "0". The second call searches for the literal characters backslash, d, and plus, which do not appear in the string, so the original text is returned unchanged.

This distinction matters when the target text contains regex metacharacters. To replace a literal dot, dollar sign, or parenthesis, replace() is the safer choice because no escaping is required:

String path = "src/main/java"; String result = path.replace(".", "/");

The same intent with replaceAll() requires escaping the dot: path.replaceAll("\\.", "/"). Forgetting the escape produces a pattern that matches every character.

Why replace() Returns a New String

String objects in Java are immutable. Every method that appears to modify a string — replace(), toUpperCase(), trim(), substring() — actually returns a new String instance. The original object is never modified.

String value = "hello"; value.replace('l', 'r'); System.out.println(value); // "hello" — the result was discarded

The return value of replace() must be assigned to a variable or used directly. Failing to capture it is a common mistake, especially for developers coming from languages with mutable string types.

Performance: Literal Replacement vs Regex

Because replace() treats its arguments as literal text, it avoids the overhead of compiling and executing a regular expression. Calling replaceAll() requires the JVM to compile the pattern, which involves parsing the regex and building internal matcher state. For a single call, the difference is negligible. For a loop processing thousands of strings, the cost accumulates.

for (String line : lines) { String cleaned = line.replace(",", ";"); // process cleaned }

When a regex pattern is genuinely needed and reused across many inputs, the Pattern class allows compiling it once:

Pattern digitPattern = Pattern.compile("\\d+"); for (String line : lines) { String cleaned = digitPattern.matcher(line).replaceAll("0"); // process cleaned }

For literal text, replace() is simpler and faster because no regex machinery is involved at all. The JVM also avoids the allocation of intermediate regex objects.

Common Mistakes with replace() and replaceAll()

The most frequent mistake is using replaceAll() when the target is literal text and forgetting to escape regex metacharacters. This produces either no replacement or an unexpected result.

String text = "file.txt"; String wrong = text.replaceAll(".", "_"); // every character becomes "_" String right = text.replace(".", "_"); // "file_txt"

A second mistake is assuming replace() modifies the original string. Since String is immutable, the original is never touched, and the result must be captured.

A third mistake is passing null as either argument. Both overloads throw NullPointerException when target or replacement is null. There is no overload that accepts null as a meaningful value, so null checks belong in the calling code when the input is untrusted.

Edge Cases and Input Behavior

When the target sequence does not appear in the string, replace() returns a String equal to the original. The implementation may return the same instance in some cases, but the contract guarantees equality, not identity. Code should never rely on reference comparison after calling replace().

When both target and replacement are empty strings, the behavior follows directly from the replacement semantics: every occurrence of the empty string is replaced, which inserts the replacement at the start, between every character, and at the end.

String text = "abc"; String result = text.replace("", "-"); System.out.println(result); // "-a-b-c-"

This edge case is rarely needed in practice, but it is worth knowing because it follows from the documented contract rather than from any special-case handling.

Choosing the Right Replacement Method

MethodFirst argumentReplacement scope
replace()Literal textAll occurrences
replaceAll()Regular expressionAll occurrences
replaceFirst()Regular expressionFirst occurrence only

Use replace() when the target is a fixed character or literal sequence and all occurrences should be replaced. This covers most text-cleaning tasks in everyday code: normalizing separators, removing known substrings, or swapping fixed tokens.

Use replaceAll() when the target must be expressed as a regular expression — digit sequences, word boundaries, or character classes.

Use replaceFirst() when only the first occurrence of a pattern should be replaced, such as replacing a single leading prefix.

For literal replacement, replace() is the right default. It avoids regex escaping bugs, reads more clearly, and skips regex compilation entirely. Reserve replaceAll() for cases where pattern matching genuinely adds value, and keep the pattern compiled and reused when it is evaluated frequently.

java string replace: Practical Usage and Code Examples | RYUSLOG DEV