All topics
library
intermediate

Regular Expressions in Java

Use Pattern and Matcher for regex operations and know the performance implications of compiled vs inline patterns.

Pattern compiles a regular expression. Matcher runs it against input.

Compiling a Pattern = building a custom maze. Each Matcher call = running a mouse through the maze. Reusing the maze (Pattern) is fast; rebuilding it every time (String.matches) is slow.

Key Concepts

1
    private static final Pattern EMAIL =
        Pattern.compile("^[\\w.+-]+@[\\w-]+\\.[\\w.]+$");
2
    Matcher m = EMAIL.matcher(input);
    if (m.matches()) { ... }
3
Compile once, into a constant. This is the mistake that matters:
4
    for (String s : millionLines)
      if (s.matches("\\d+"))  { ... }      // recompiles every iteration
5
String.matches, replaceAll and split all compile the pattern on every call. In a loop that is hundreds of times slower than a pre-compiled Pattern.
String.matchesreplaceAllsplitPattern
6
matches and find are different questions.
    matches()    must the WHOLE input match?
    find()       is there a match anywhere? call again for the next
    lookingAt()  does the match start at the beginning?
matchesfind
7
Capture groups pull pieces out:
    Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
    Matcher m = p.matcher("2026-03-15");
    if (m.matches()) {
      m.group(1);        // "2026"
      m.group(0);        // the whole match
    }
8
Named groups read better once there are more than two:
9
    Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})");
    m.group("year");
10
The syntax worth memorising.
    \d digit    \w word char    \s whitespace    . any char
    *  zero or more    +  one or more    ?  zero or one
    {2,5} a range      ^ start          $ end
    [a-z] class        [^a-z] negated
    (x) capturing      (?:x) non-capturing
11
Flags go in compile:
    Pattern.compile("^abc$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
compile
12
Threading: Pattern is safe to share, Matcher is not. So a static Pattern field is correct, and a static Matcher is a race condition.
PatternMatcher
13
Catastrophic backtracking is the production hazard.
    Pattern.compile("(a+)+b").matcher("aaaaaaaaaaaaaaaaaaaaaaaaaa!");
14
Nested quantifiers make the engine try exponentially many splits, and one request pins a CPU for minutes. That is a denial of service if the pattern or the input comes from a user.
15
What the interviewer is probing.1. "Why compile a Pattern into a constant?" Probing: the cost people leave in loops. Stalls: "It is tidier." Moves up: String.matches, replaceAll and split compile the pattern on every call, which in a loop is orders of magnitude slower than a reused Pattern.
16
2. "Is Matcher thread-safe?" Probing: what can be shared. Stalls: "Yes, like Pattern." Moves up: Pattern is safe to share; Matcher is not, so a static Matcher is a race condition.
17
3. "What is catastrophic backtracking?" Probing: the production hazard. Stalls: "A slow regex." Moves up: nested quantifiers like (a+)+b make the engine try exponentially many splits, so one request pins a CPU for minutes — a denial of service if the input is user-supplied.
18
4. "matches versus find?" Probing: a distinction that silently changes behaviour. Stalls: "The same." Moves up: matches requires the entire input to match; find looks for a match anywhere and can be called repeatedly.