replace() and replaceAll()

replace() swaps every occurrence of literal text; replaceAll() and replaceFirst() treat the first argument as a regular expression.

Signature
public String replaceAll(String regex, String replacement)
  • Added in Java Java 1.4

Parameters

ParameterTypeDescription
$regexStringThe regular expression to match. For replace(), the literal target text instead.
$replacementStringThe replacement. In replaceAll and replaceFirst, $n refers to a capture group and backslash escapes the next char.

Return value

StringA new String with every match of regex replaced. replace(CharSequence, CharSequence) does the same for literal text.

Errors

PatternSyntaxException if regex is invalid; IllegalArgumentException or IndexOutOfBoundsException if replacement refers to a missing group or ends with a lone backslash; NullPointerException for null arguments.

Changelog

  • PHP Java 5replace(CharSequence target, CharSequence replacement) was added for literal text. replace(char, char) has existed since Java 1.0.

String has four replace methods and the names hide the most important difference.

MethodFirst argumentReplaces
replace(char, char)a charevery occurrence
replace(CharSequence, CharSequence)literal textevery occurrence
replaceAll(String, String)a regular expressionevery match
replaceFirst(String, String)a regular expressionthe first match

So replace already replaces all occurrences. The "All" in replaceAll is about regex, not about how many. All of them return a new String; the original never changes, so assign the result.

The regex traps

In replaceAll, characters such as . | $ ( ) [ ] * + ? and backslash have special meaning. "a.b".replaceAll(".", "/") gives ///, because . matches any char. If you want literal text, use replace, or wrap the pattern in Pattern.quote.

The replacement is special too. $1 inserts capture group 1 and a backslash escapes the next char. Inserting a price such as $25.00 or a Windows path with replaceAll fails or corrupts the text. Wrap user data in Matcher.quoteReplacement, or use replace when no pattern is needed.

Performance

replaceAll compiles its pattern on every call. That is fine for a one-off, but in a request path that runs thousands of times a second, hold a static final Pattern and call pattern.matcher(s).replaceAll(...). replace with literal text does not use regex at all and is the fastest choice.

Not a security tool

Stripping <script> or quotes with replace is not escaping. Attackers nest or encode payloads to survive one pass. Use a proper HTML encoder when writing HTML, and a PreparedStatement for SQL.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Building URL slugs for blog posts or product pages from their titles.
  • Masking email addresses and tokens in log lines before they are written.
  • Collapsing repeated whitespace in a search query before it reaches the database.

Frequently asked questions

What is the difference between replace and replaceAll in Java?

Both replace every occurrence. replace treats its arguments as literal text; replaceAll treats the first as a regular expression and the second as a replacement pattern where $ and backslash are special.

Why does replaceAll(".", ...) replace every character?

In a regular expression . matches any char. Escape it as "\\.", use Pattern.quote("."), or use replace(".", ...) for literal text.

How do I replace only the first occurrence?

Use replaceFirst(regex, replacement). For literal text, wrap the target in Pattern.quote and the replacement in Matcher.quoteReplacement.

More examples

A dollar sign in the replacement

replaceAll reads $2 in the replacement as a reference to capture group 2, which does not exist. replace treats the value literally, and Matcher.quoteReplacement escapes it when you do need a regex.

Example · java
void main() {
    String template = "Total: AMOUNT";
    String amount = "$25.00";
    IO.println(template.replace("AMOUNT", amount));
    try {
        IO.println(template.replaceAll("AMOUNT", amount));
    } catch (IndexOutOfBoundsException e) {
        IO.println("replaceAll failed: " + e.getMessage());
    }
    IO.println(template.replaceAll("AMOUNT", Matcher.quoteReplacement(amount)));
}
// Output:
// Total: $25.00
// replaceAll failed: No group 2
// Total: $25.00

Rewriting with capture groups

Groups let the replacement keep part of each match: the domain stays and the local part is hidden. Masking personal data this way before logging is a common requirement under data protection rules.

Example · java
void main() {
    String log = "[email protected] ip=10.0.0.7 [email protected]";
    IO.println(log.replaceAll("([\\w.]+)@([\\w.]+)", "***@$2"));

    String date = "2026-10-13";
    IO.println(date.replaceAll("(\\d{4})-(\\d{2})-(\\d{2})", "$3/$2/$1"));
}
// Output:
// user=***@example.com ip=10.0.0.7 user=***@test.org
// 13/10/2026

A precompiled Pattern for a hot path

Compiling the patterns once avoids recompiling them on every request, which String.replaceAll would do. Each run of non-slug chars becomes one dash, then a leading or trailing dash is removed.

Example · java
static final Pattern NON_SLUG = Pattern.compile("[^a-z0-9]+");
static final Pattern EDGE_DASH = Pattern.compile("^-|-$");

String slugify(String title) {
    String lower = title.strip().toLowerCase(Locale.ROOT);
    String dashed = NON_SLUG.matcher(lower).replaceAll("-");
    return EDGE_DASH.matcher(dashed).replaceAll("");
}

void main() {
    IO.println(slugify("Spring Boot 4.1: What's New?"));
    IO.println(slugify("  --Hello,  World!--  "));
}
// Output:
// spring-boot-4-1-what-s-new
// hello-world

Discussion

  • Be the first to comment on this lesson.