Back to Blog
Java

Java String.split() Regex: Splitting with Patterns

Java String.split() takes a regex, not a literal delimiter. Learn how to escape metacharacters, use the limit parameter, and reuse compiled Pattern objects for better performance.

String.splitJava regexPattern.quoteRegular expressionsJava strings
A stylized Java string being split into segments by a regex pattern, with a magnifying glass over the pattern.

When you call String.split() in Java, the first argument is a regular expression, not a literal delimiter. That distinction is the source of both the method's power and its most common pitfalls. For example, "a.b.c".split(".") returns an empty array because . matches any character. The correct pattern is Pattern.quote("."), or an escaped dot in the regex. Understanding how the regex is interpreted is essential for writing reliable string-splitting code.

How String.split() Interprets Its Regex Argument

The split method takes a regular expression string, compiles it internally, and splits the input around matches of that pattern. The method discards trailing empty strings by default, which often surprises developers. For instance, "a,b,".split(",") returns ["a", "b"], not ["a", "b", ""]. Each match of the regex becomes a delimiter.

Consider a simple comma-separated value:

String data = "apple,banana,cherry"; String[] fruits = data.split(","); // fruits = ["apple", "banana", "cherry"]

Here the regex is just a comma, so it behaves like a literal. But when the delimiter is a regex metacharacter such as ., |, *, +, ?, ^, $, [, ], (, ), {, }, or \, you must escape it or use Pattern.quote().

Using Pattern.quote() for Literal Delimiters

If you need to split on a literal string that contains regex metacharacters, the safest approach is Pattern.quote(). This method wraps the input in \Q and \E, which tells the regex engine to treat everything inside as literal text.

String path = "/usr/local/bin"; String[] parts = path.split(Pattern.quote("/")); // parts = ["", "usr", "local", "bin"]

The leading empty string appears because the input starts with the delimiter. String.split() removes only trailing empty strings by default. Without Pattern.quote(), splitting on a pipe character fails because | means alternation:

String csv = "a|b|c"; String[] bad = csv.split("|"); // splits into individual characters String[] good = csv.split("\\|"); // works, but escaping manually is error-prone String[] best = csv.split(Pattern.quote("|")); // clear and correct

Pattern.quote() is especially useful when the delimiter comes from user input or configuration, where you cannot predict which characters will appear.

The Limit Parameter and Its Effects

The split method has an overload that accepts a second argument, limit. This parameter controls how many times the pattern is applied and affects the length of the resulting array.

  • If limit is positive, the pattern is applied at most limit - 1 times, and the last element of the array contains the remainder of the string.
  • If limit is zero, the pattern is applied as many times as possible, and trailing empty strings are discarded. This is the default behavior.
  • If limit is negative, the pattern is applied as many times as possible, but trailing empty strings are kept.
String input = "a,b,c,"; String[] zero = input.split(","); // ["a", "b", "c"] String[] negative = input.split(",", -1); // ["a", "b", "c", ""] String[] positive = input.split(",", 2); // ["a", "b,c,"]

The negative limit is useful when you need to preserve trailing empty fields, such as when parsing CSV data where empty columns matter.

Common Regex Patterns for Splitting

Beyond simple delimiters, split accepts any valid regex. This allows you to split on whitespace, multiple characters, or complex patterns.

To split on any whitespace (spaces, tabs, newlines), use \s+:

String sentence = "The quick brown fox"; String[] words = sentence.split("\\s+"); // words = ["The", "quick", "brown", "fox"]

To split on commas or semicolons, use a character class:

String mixed = "a;b,c;d"; String[] items = mixed.split("[;,]"); // items = ["a", "b", "c", "d"]

You can also use grouping and alternation for more complex delimiters. For example, splitting on a comma followed by optional whitespace:

String data = "apple, banana, cherry"; String[] fruits = data.split(",\\s*"); // fruits = ["apple", "banana", "cherry"]

The regex engine handles standard Java patterns, so you can use anchors, quantifiers, and lookarounds if needed. Keep in mind that split locates each delimiter match and removes it from the result.

Trailing Empty Strings and How to Keep Them

As mentioned, split with a zero limit removes trailing empty strings. This behavior is often overlooked and can cause bugs when processing data that ends with a delimiter. To keep those empty strings, use a negative limit.

String csvLine = "1,2,3,"; String[] withTrailing = csvLine.split(",", -1); // ["1", "2", "3", ""] String[] withoutTrailing = csvLine.split(","); // ["1", "2", "3"]

This is particularly important when reconstructing records or when the number of fields must be consistent. If you are parsing a file where each line should have the same number of columns, using split without a negative limit will silently drop the final empty column.

Performance: Reusing a Compiled Pattern

Each call to String.split() normally compiles the regex pattern from scratch. Some JDK versions include a fast path for simple one-character literal delimiters, but that special case does not apply to arbitrary regular expressions. If you are splitting many strings with the same delimiter, reusing a compiled Pattern avoids recompilation and keeps the regex in one place.

Pattern commaPattern = Pattern.compile(","); for (String line : lines) { String[] fields = commaPattern.split(line); // process fields }

Pattern.split() behaves like String.split() with a zero limit, but it avoids recompiling the regex. For a small number of splits, the difference is negligible, but in a tight loop or when processing large volumes of data, reusing a compiled pattern can reduce CPU usage and memory allocation.

There is also Pattern.split(CharSequence, int), which corresponds to the limit overload. Using the compiled pattern is a simple optimization that costs little and improves maintainability if the pattern is reused.

When to Use Pattern.split() Instead of String.split()

Choose Pattern.split() when you are splitting repeatedly with the same pattern, especially in performance-sensitive code. String.split() is fine for one-off splits where the pattern is used only once. The decision is based on the frequency of the operation and whether the regex is static.

If the regex is dynamic (for example, built from user input), you cannot precompile it easily, but you can still use Pattern.quote() to ensure literal interpretation. In general, if you find yourself writing the same delimiter string in multiple places, extracting it as a Pattern constant improves both performance and readability.

Pattern.split() returns the same array type as String.split(), so there is no API difference. The only tradeoff is the extra Pattern object, which is negligible.

Edge Cases: Empty Pattern and Unicode

An empty regex "" matches at every position, so "abc".split("") returns an array of individual characters: ["a", "b", "c"]. This can be useful for splitting into characters, but it also splits surrogate pairs incorrectly for supplementary Unicode characters. For proper code-point iteration, use codePoints() instead.

The regex engine operates on UTF-16 code units by default. A pattern such as . matches one code unit, not one code point, so characters outside the Basic Multilingual Plane (such as emojis) need special care. If you need to work by code point, prefer iterating with codePoints() rather than relying on a zero-width split.

Another edge case is when the regex can match an empty string. For example, an optional pattern such as b? matches empty strings and can produce unexpected split positions. Avoid patterns that can match empty strings unless you fully understand the consequences.

Finally, split does not preserve the delimiters themselves. If you need to keep the delimiters, use Pattern.matcher() with a custom loop. For most splitting tasks, split is sufficient, but knowing its behavior with regex is key to avoiding subtle bugs.

Java String.split() Regex: Usage, Limit, and Performance | RYUSLOG DEV