HuntExams Academy logo
JavaIntermediate#strings

How do you split a String and handle edge cases with delimiters that are regex special characters?

Answer

String.split(String regex) takes a regular expression, not a literal string. So delimiters such as . | + * ? ( ) [ ] { } ^ $ \ must be escaped, or you get the regex meaning instead of the character. The classic bug: "a.b.c".split(".") returns an empty array, because "." matches every character. Correct forms are split("\\.") in Java source, or the safest general solution, split(Pattern.quote(delimiter)) \u2014 Pattern.quote wraps anything in \Q...\E so it is treated literally. Always use it when the delimiter comes from user input or configuration. Other edge cases interviewers probe: - Trailing empty strings are dropped by default: "a,b,,,".split(",") gives [a, b]. Pass a negative limit, split(",", -1), to keep them. Leading empties are kept: ",a".split(",") gives ["", a]. - Splitting an empty string returns an array of length 1 containing "" \u2014 not an empty array. - A positive limit caps the number of pieces and leaves the remainder intact in the last element, which is exactly what you want for "key=value" pairs whose value contains '='. - Whitespace: split("\\s+") collapses runs of whitespace, but a leading space still produces an empty first element, so trim() or strip() first. - Performance: split compiles the regex on every call. Inside a loop, precompile a Pattern and use pattern.split(), or use indexOf for a single-character delimiter. - Alternatives: StringTokenizer, or Guava Splitter with trimResults() and omitEmptyStrings(). - CSV is not a split problem \u2014 quoted fields containing commas need a real parser such as OpenCSV or Commons CSV.

Example

// The trap
"a.b.c".split(".").length;                 // 0 -- '.' matches everything

// Three correct ways
"a.b.c".split("\\.");                      // [a, b, c]
"a.b.c".split(Pattern.quote("."));         // [a, b, c]  safest
"a|b|c".split(Pattern.quote("|"));         // [a, b, c]

// Trailing empties
",a,b,,".split(",");                       // ["", a, b]
",a,b,,".split(",", -1);                   // ["", a, b, "", ""]

// A positive limit keeps the remainder
"key=a=b".split("=", 2);                   // [key, "a=b"]

// Runs of whitespace
"  Hello   World  ".trim().split("\\s+");  // [Hello, World]

// Reuse a compiled pattern in loops
private static final Pattern PIPE = Pattern.compile(Pattern.quote("|"));
for (String line : lines) {
    String[] cols = PIPE.split(line, -1);
}

// Empty input
"".split(",").length;                      // 1, containing ""

Detailed explanation

Java’s String.split(String regex) accepts a regular expression, not a literal delimiter. This matters because characters such as '.', '|', and '*' have regex meanings: they can match unexpected text or cause PatternSyntaxException. For example, "a.b.c".split(".") returns an empty array because '.' matches every character here, and the resulting trailing empty strings are discarded. Interviewers expect you to explain this behaviour, rather than simply memorise an escaping rule.

For a known dot delimiter, use split("\\."). There are two interpretation layers: Java converts the source literal "\\." into the regex \., and the regex engine interprets that as a literal dot. For delimiters supplied through configuration or user input, use split(Pattern.quote(delimiter)). Pattern.quote produces a regex that matches the entire delimiter literally, including multi-character delimiters and embedded quoting markers. Use quoting when the input represents a literal separator; do not quote an intentionally supplied regex such as "\\s+". Pattern belongs to java.util.regex.

The limit argument controls both splitting and empty-field handling. The default limit is zero, which discards trailing empty fields: "a,b,,,".split(",") produces ["a", "b"]. A negative limit preserves them, making split(Pattern.quote(delimiter), -1) useful for positional records. A positive limit permits at most limit minus one splits and preserves the unsplit remainder: "key=a=b".split("=", 2) produces ["key", "a=b"]. A positive-width delimiter match at the beginning produces a leading empty field; a zero-width match there does not. Empty input split on a comma produces one element containing "", because no delimiter matches.

Whitespace and performance need separate attention. split("\\s+") handles runs of whitespace but can create a leading empty field; trim() or Java 11’s strip() can remove surrounding whitespace first. Handle blank input separately if you want zero tokens. Default regex \s is not fully Unicode-aware. For repeated regex splitting, reuse a compiled Pattern, although String.split has implementation-specific fast paths for simple delimiters, so it does not always compile a regex. Validate null inputs and empty delimiters explicitly. Finally, quoted CSV fields require a CSV parser, not a comma split.

Key points to remember

  • Use split("\\.") for a literal dot, or Pattern.quote(delimiter) for an arbitrary literal delimiter.
  • The default limit of zero drops trailing empty strings; a negative limit preserves them.
  • A positive limit caps the number of elements and leaves the remaining text in the final element.
  • Leading positive-width matches preserve an empty first field; empty input with no match returns [""].
  • Reuse Pattern for repeated regex splitting, and use a dedicated parser for quoted CSV.

Common mistakes candidates make

  • Passing regex metacharacters directly, or forgetting that Java string literals require an additional escaping layer.
  • Using the default split overload for positional data and silently losing trailing empty columns.
  • Assuming strip().split("\\s+") returns zero elements for blank input or handles all Unicode whitespace by default.

Likely follow-up questions

Why use Pattern.quote instead of manually adding backslashes?

Pattern.quote safely treats the entire delimiter as literal text, including multi-character separators and embedded \E sequences. Manual escaping is easy to get wrong; Matcher.quoteReplacement is not a substitute because it escapes replacement text, not regex patterns.

How should null or empty delimiters be handled?

Reject or explicitly define their meaning before splitting: a null delimiter causes NullPointerException, while an empty delimiter becomes an empty regex with zero-width matching behaviour. Pattern.quote("") does not turn an empty separator into a no-op.

When should you avoid String.split?

Use indexOf and substring when you only need the first literal separator, or reuse a compiled Pattern for repeated complex regex splitting. For CSV with quoted commas, escaped quotes, or multiline fields, use a parser such as Apache Commons CSV or OpenCSV.

Interview tip: Start with the literal-versus-regex distinction, demonstrate the dot-delimiter bug, and then explain negative and positive limits with small examples.

Related Interview Questions

1
JavaIntermediate#collections

What is the difference between Set implementations HashSet, LinkedHashSet, and TreeSet?

Open
2
JavaIntermediate#collections

What is the difference between Iterator and ListIterator?

Open
3
JavaIntermediate#collections

What is the difference between Deque and Queue?

Open