String Replace

Su Suriya Ravichandran Updated 14 Nov 2026
5 min read ·Lesson 97 of 133

Replacing text means producing a new string in which some characters or substrings have been swapped for others. Java provides four replacement methods: two that treat their arguments as literal text and two that treat them as regular expressions. Knowing which kind you are using avoids the most common surprises, especially with characters like ., $, and ``.

MethodSearch argumentReplaces
replace(char old, char new)A single characterEvery occurrence
replace(CharSequence target, CharSequence replacement)Literal textEvery occurrence
replaceAll(String regex, String replacement)Regular expressionEvery match
replaceFirst(String regex, String replacement)Regular expressionThe first match only

As with all String methods, the original string is never modified; each method returns a new string.

replace with Characters

String date = "2026-11-11";
String slashed = date.replace('-', '/');      // "2026/11/11"
System.out.println(date);                     // 2026-11-11 (unchanged)

replace with Text

String msg = "Hello NAME, welcome NAME!";
String out = msg.replace("NAME", "Ada");      // "Hello Ada, welcome Ada!"

Despite the name difference from replaceAll, replace replaces every occurrence, not just the first. The search text and the replacement are both literal: no character has a special meaning.

"a.b.c".replace(".", "-");          // "a-b-c"
"cost: $5".replace("$5", "$7");     // "cost: $7"

Replacements are applied left to right without overlap, and the result is not re-scanned:

"aaa".replace("aa", "b");           // "ba": the first two a's match; the third is left alone

To delete text, replace it with an empty string:

"(044) 2345-6789".replace("(", "").replace(")", "").replace("-", "");   // "044 23456789"

replaceAll: Regular Expressions

replaceAll interprets its first argument as a regular expression, which lets one call match a whole class of text:

"a1b22c333".replaceAll("\\d+", "#");                    // "a#b#c#"   runs of digits
"  Too   many    spaces\there  ".strip().replaceAll("\\s+", " ");   // "Too many spaces here"
"4111-1111-1111-1234".replaceAll("\\D", "");            // "4111111111111234"   non-digits removed

Common patterns:

PatternMatches
0d / 1DA digit / a non-digit
0s / 1s+A whitespace character / a run of whitespace
0wA letter, digit, or underscore
[aeiou]Any one of the listed characters
[^a-z0-9]Any character not in the set
.Any character
^ / $Start / end of the string

In a Java string literal, the backslash itself must be escaped, so the regex \d is written "0d".

The literal-versus-regex trap

Because . means "any character" in a regex, these two calls do very different things:

"a.b.c".replace(".", "-");          // "a-b-c"   literal dot
"a.b.c".replaceAll(".", "-");       // "-----"   every character

To match a special character literally in replaceAll, escape it ("0.") or quote the whole pattern with Pattern.quote(text). If you do not need a pattern, use replace.

Special characters in the replacement

In replaceAll and replaceFirst, the replacement string is also special: $1, $2, ... insert captured groups, and `` escapes characters. This makes group-based rearrangement possible:

"2026-11-11".replaceAll("(\\d{4})-(\\d{2})-(\\d{2})", "$3/$2/$1");   // "11/11/2026"

The parentheses capture the year, month, and day; $3/$2/$1 reassembles them in a different order.

The downside is that a replacement containing a literal $ breaks:

"Price: X".replaceAll("X", "$5");      // IndexOutOfBoundsException: No group 5
"Price: X".replace("X", "$5");         // "Price: $5"
"Price: X".replaceAll("X", Matcher.quoteReplacement("$5"));   // "Price: $5"

When the replacement comes from user input or data (prices, passwords, file paths on Windows), either use replace or wrap the value with Matcher.quoteReplacement.

replaceFirst

replaceFirst works like replaceAll but stops after the first match:

"one two two".replaceFirst("two", "2");       // "one 2 two"
"   indented".replaceFirst("^\\s+", "");      // "indented"

There is no literal-text replaceFirst. To replace only the first occurrence of fixed text, quote it: s.replaceFirst(Pattern.quote(target), Matcher.quoteReplacement(value)), or use indexOf and substring.

Replacing with Computed Values

When each match needs a different replacement computed in code, Matcher.replaceAll (Java 9+) accepts a function:

Pattern price = Pattern.compile("\\d+");
String doubled = price.matcher("2 pens and 3 books")
        .replaceAll(m -> String.valueOf(Integer.parseInt(m.group()) * 2));
// "4 pens and 6 books"

Case-Insensitive Replacement

There is no replaceIgnoreCase. Use a regex with the (?i) flag, quoting the search text so it is treated literally:

String text = "Java, JAVA and java";
String out = text.replaceAll("(?i)" + Pattern.quote("java"), "Kotlin");   // "Kotlin, Kotlin and Kotlin"

Performance Notes

  • replace(CharSequence, CharSequence) does not use regular expressions internally; it is the fastest choice for literal text.
  • String.replaceAll compiles its pattern on every call. In a loop over many strings, compile a Pattern once and use pattern.matcher(s).replaceAll(...).
  • Chaining many replace calls scans the string once per call. For a handful of replacements this is fine; for templates with many placeholders, a single pass with a Matcher or a StringBuilder scales better.

Practical Example: Templates and Masking Sensitive Data

import java.util.*;
import java.util.regex.Matcher;

public class Rep {
    static String fill(String template, Map<String, String> values) {
        String out = template;
        for (Map.Entry<String, String> e : values.entrySet()) {
            out = out.replace("{{" + e.getKey() + "}}", e.getValue());
        }
        return out;
    }

    static String maskCard(String card) {
        String digits = card.replaceAll("\\D", "");                 // keep digits only
        return "**** **** **** " + digits.substring(digits.length() - 4);
    }

    static String maskEmail(String email) {
        return email.replaceAll("(?<=.).(?=[^@]*@)", "*");          // keep first char and domain
    }

    public static void main(String[] args) {
        String template = "Hi {{name}}, your order {{order}} of {{amount}} ships on {{date}}.";
        System.out.println(fill(template, new LinkedHashMap<>(Map.of(
                "name", "Ada", "order", "#A-1042", "amount", "₹1,499.00", "date", "14 Nov"))));

        System.out.println(maskCard("4111-1111-1111-1234"));
        System.out.println(maskEmail("ada.lovelace@gocourse.in"));

        String messy = "  Too   many    spaces\there  ";
        System.out.println("[" + messy.strip().replaceAll("\\s+", " ") + "]");

        System.out.println("Price: X".replaceAll("X", Matcher.quoteReplacement("$5")));
    }
}

Output:

Hi Ada, your order #A-1042 of ₹1,499.00 ships on 14 Nov.
**** **** **** 1234
a***********@gocourse.in
[Too many spaces here]
Price: $5

Each task uses the right kind of replacement:

  • fill uses literal replace. Placeholder names and values can contain any characters, including $, #, and ₹, without being misinterpreted.
  • maskCard uses replaceAll("0D", "") to strip every non-digit regardless of how the number was formatted (spaces, dashes), then keeps only the last four digits. Payment systems display cards this way so that full numbers never appear in logs or receipts.
  • maskEmail uses a regex with lookarounds. (?<=.) requires at least one character before the match, and (?=[^@]*@) requires that an @ still lies ahead. Every character of the local part except the first is replaced with *, while the domain stays readable.
  • The whitespace cleanup collapses runs of spaces and tabs into single spaces.
  • The last line shows the safe way to put a literal $ into a regex replacement.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about String Replace and get answers drawn from it.

Signed-in readers only.