skip to content

What is a non-capturing group (?:...) in Java regex, and why would you use one instead of a plain ()?

level: middleimportance: should knowfreq 62%

answer

  1. (?:...) = group without capture or number
  2. use when you only need a quantifier/alternation scope
  3. keeps real groups' numbers small and stable
  4. same match behavior, only metadata differs

basics

~20 s

A non-capturing group (?:...) groups part of a pattern so a quantifier or alternation applies to it, but it does not capture or get a group number. Use it when you only need grouping, not the captured text.

solid answer

~50 s

A non-capturing group is written (?:...). It behaves like an ordinary group for structural purposes — a quantifier such as + or an alternation | applies to everything inside — but it does not capture text and is not assigned a group number. You use it when you need to bundle a sub-pattern but don't care about reading it back: for example (?:ab)+ to repeat 'ab', or (?:com|org|net) for a set of alternatives. The benefit is twofold: it keeps your group numbering clean, so the groups you actually care about keep small, predictable indices instead of being pushed up by throwaway groups; and it avoids the small bookkeeping cost of capturing. It also makes intent explicit to readers: 'this paren is only for grouping.' Functionally the match result is identical to a capturing group; only the numbering and capture set differ.

code

java · 6 lines
java
Pattern p = Pattern.compile("(a)(?:b)(c)");
Matcher m = p.matcher("abc");
m.matches();
System.out.println(m.groupCount()); // 2  (the (?:b) is not counted)
System.out.println(m.group(1));      // a
System.out.println(m.group(2));      // c  (not 'b')

go deeper

for a junior

Knows (?:...) groups without capturing and is used for quantifiers/alternation.

for a middle

Explains the numbering-stability and minor-perf benefits and that match behavior is unchanged.

for a senior

Recommends non-capturing as the default for pure structure, and recognizes the renumbering fragility it prevents.

for a principal

Discusses regex maintainability/perf at scale, related (?=)/(?i:) families, and team conventions for group hygiene.

## Recap: what a capturing group does Writing `( ... )` in a regex creates a **capturing group** — it bundles a sub-pattern AND remembers (captures) the substring it matched, assigning it a number so you can read it with `group(n)`. Numbering is by the position of each opening `(`. ## The problem capturing groups can cause Sometimes you put parentheses around a sub-pattern **only** to apply a quantifier or an alternation to it — you have no interest in the captured text. Two issues arise: 1. **Number pollution.** Every `(` shifts the numbering. If you wrap a throwaway sub-pattern in `()`, the groups you actually care about get larger, less stable numbers. Adding or removing one such group renumbers everything after it, silently breaking `group(3)` calls or `$3` replacements. 2. **Minor overhead.** The engine allocates bookkeeping to record each capture's start/end, which is wasted work if you never read it. ## The solution: non-capturing groups A **non-capturing group** is written `(?:...)`. The `?:` immediately after the opening parenthesis tells the engine: "group these tokens, but do not capture and do not assign a number." - `(?:ab)+` matches `ababab` — the `+` applies to the whole `ab`, just like a capturing group would, but no group number is consumed. - `https?://(?:www\.)?example\.com` — the `(?:www\.)?` makes the `www.` prefix optional without creating a capture. ## What it does NOT change The **matching behavior is identical** to a capturing group: the same strings match. What differs is purely the *result metadata* — non-capturing groups don't appear in `group(n)`, `start(n)`, `end(n)`, and don't increment `groupCount()`. ## How numbering interacts Consider `(a)(?:b)(c)`: - group 1 = `a` - the `(?:b)` is skipped for numbering - group 2 = `c` So non-capturing groups are essentially invisible to the numbering scheme — capturing groups before and after them number contiguously. ## When to use which - Use **capturing `()`** when you will read the substring back, use a backreference, or reference it in a replacement (`$1`). - Use **non-capturing `(?:)`** when you only need grouping for a quantifier/alternation. It is the better default for pure structure: clearer intent, stable numbering, slightly cheaper. ## Related constructs Lookaround groups `(?=...)`, `(?!...)`, `(?<=...)`, `(?<!...)` and the inline-flag group `(?i:...)` are also non-capturing. Atomic groups `(?>...)` likewise don't capture. The `(?:` form is the plain non-capturing variant.

  • Does a non-capturing group change which strings the pattern matches?
    No. Matching behavior is identical to a capturing group; only the capture/numbering metadata differs.
  • Name two other regex constructs that also don't capture.
    Lookarounds like (?=...) and (?<=...), and inline-flag groups like (?i:...); atomic groups (?>...) also don't capture.

It's like using parentheses in arithmetic just to set precedence — (2+3)*4 — versus naming a variable you'll reuse later. Sometimes you only need the precedence, not the name.

saying these in an interview costs you the question

  • Thinking (?:...) changes what matches — it doesn't
  • Believing non-capturing groups still get a number you can read
  • Using capturing () everywhere and then being surprised by renumbering bugs
  • Confusing (?:...) with lookahead (?=...)

context