skip to content

Replacement & Splitting

replaceAll and replaceFirst with $1 group references, the quoting helpers for literal dollars and backslashes, and split with its limit argument and trailing-empty behavior. The split limit is the detail people get wrong in production.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

In Java, what is the difference between String.replaceAll and String.replaceFirst, and how do they differ from String.replace?

level: juniorimportance: must knowfreq 70%

answer

  1. replaceAll/replaceFirst = regex; replace = literal
  2. All return a NEW string (immutable)
  3. First arg is a pattern, replacement arg is ALSO special ($, \)
  4. replaceFirst stops after one match
  5. replace(".",..) is safe; replaceAll(".",..) matches everything

basics

~10 s

replaceAll changes every match of a regex; replaceFirst changes only the first match. Both treat their first argument as a regular expression. String.replace is different: it works on plain literal text, not regex.

solid answer

~40 s

All three return a new String (Strings are immutable). replaceAll(regex, repl) replaces every substring matching the regex; replaceFirst(regex, repl) replaces only the first match. The first argument of both is compiled as a regular expression, so characters like . [ ] ( ) * + ? | \ are special. Crucially, the replacement string is also interpreted: $1 is a group back-reference and a backslash escapes, so a literal $ or \ in the replacement must be escaped or run through Matcher.quoteReplacement. By contrast, String.replace(CharSequence, CharSequence) takes literal text on both sides, no regex and no replacement metacharacters, so it is the right choice when you just want to swap one fixed substring for another.

go deeper

for a junior

Knows replaceAll changes all matches, replaceFirst only the first, and that both return a new string.

for a middle

Explains that the first argument is a regex (so . [ ] etc. are special) and that String.replace is the literal alternative.

for a senior

Also flags the replacement-string trap ($/) and the per-call compilation cost, recommending Pattern.compile for hot paths.

for a principal

Frames API choice as a correctness-and-performance decision, sets team conventions (literal replace by default, quoteReplacement for user data), and reasons about immutability/GC pressure at scale.

## What these methods do Java's `String` class has several substitution methods. Two of them are **regex-based** and one is **literal**. - A **regular expression (regex)** is a small pattern language for describing sets of strings. For example the pattern `\d+` means "one or more digits". In a regex, certain characters are *metacharacters* with special meaning: `. ^ $ * + ? ( ) [ ] { } | \`. - A **literal** string is taken character-for-character with no special meaning. ### `replaceAll(String regex, String replacement)` Compiles `regex` as a pattern, scans the whole string, and replaces **every** non-overlapping match with `replacement`. Returns a brand-new `String` (the original is never mutated, because Java strings are immutable). ### `replaceFirst(String regex, String replacement)` Same as `replaceAll` but stops after the **first** match. ### `replace(CharSequence target, CharSequence replacement)` This one is **not** regex. Both arguments are literal text. It replaces every occurrence of the literal `target`. There is also `replace(char, char)`. ## The two traps **Trap 1 — the pattern argument is a regex.** `"a.b.c".replaceAll(".", "-")` does NOT replace dots; `.` means "any character", so you get all dashes. To replace literal dots use `replaceAll("\\.", "-")` (the `\\.` is the Java source for the two-character regex `\.`) or, simpler, `replace(".", "-")`. **Trap 2 — the replacement argument is also special.** In the *replacement* string of `replaceAll`/`replaceFirst`, `$` introduces a group reference (`$1`, `$2`, …) and `\` is an escape. So `replaceAll("x", "$5")` throws because there is no group 5, and inserting a literal `$` requires `\$` or `Matcher.quoteReplacement("$")`. ## When to use which - Fixed substring swap, performance-sensitive, no pattern needed → **`replace`** (no regex compilation, no surprises). - Pattern-based, change all → **`replaceAll`**. - Pattern-based, change only the first → **`replaceFirst`**. ## Cost note `replaceAll`/`replaceFirst` compile the regex on every call. In a hot loop, precompile once with `Pattern.compile(...)` and reuse `matcher.replaceAll(...)`.

  • Why does "1.2.3".replaceAll(".", ",") produce all commas instead of "1,2,3"?
    Because . in regex means 'any character', so every character matches and is replaced. Use replaceAll("\\.", ",") or replace(".", ",").
  • If you call replaceAll thousands of times with the same pattern, what's the optimization?
    Precompile with Pattern.compile once and reuse its Matcher.replaceAll, avoiding recompiling the regex on every call.

saying these in an interview costs you the question

  • Thinking String.replace uses regex (it does not)
  • Assuming replaceAll's pattern argument is literal text
  • Forgetting the methods return a new string and trying to mutate in place
  • Not knowing $ and \ are special in the replacement string too

context

open as a page

How does the limit argument to String.split (and Pattern.split) work, and what is the default trailing-empty-string behavior?

level: seniorimportance: must knowfreq 62%

basics

~20 s

split(regex) with no limit (or limit 0) removes trailing empty strings. A positive limit caps the number of pieces and keeps trailing empties; a negative limit keeps ALL trailing empties with no cap. Limit 0 is the default and the source of most surprises.

open as a page

How do capturing-group back-references like $1 work in a Java regex replacement string, and how do you insert a literal $ or backslash?

level: middleimportance: should knowfreq 58%

basics

~20 s

Inside the replacement string, $1, $2, ... insert the text captured by the matching parentheses (groups) of the pattern. To put a literal $ or \ in the output instead, escape it as $ / \, or wrap the whole replacement in Matcher.quoteReplacement.

open as a page

What does Pattern.quote do, and when must you use it when building a Java regex?

level: middleimportance: should knowfreq 50%

basics

~20 s

Pattern.quote(s) returns a regex that matches the string s exactly, treating every character as literal. Use it whenever you build a pattern from text that might contain regex metacharacters like . * + ( ) [ ], especially user input.

open as a page

For high-throughput replacement, when should you use Matcher.replaceAll / appendReplacement instead of String.replaceAll, and why?

level: seniorimportance: should knowfreq 40%

basics

~10 s

String.replaceAll recompiles the regex on every call. In hot paths, compile the pattern once with Pattern.compile and reuse a Matcher (matcher.replaceAll). For replacements computed from each match, use appendReplacement/appendTail or replaceAll with a Function.

open as a page