Java String split: Syntax, Edge Cases, and Performance
java string split: Learn how Java String.split works, including regex syntax, the limit parameter, trailing empty string behavior, and performance tradeoffs.
java string split requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
The split method in java.lang.String is the standard way to break a string into parts based on a delimiter. Its behavior depends on two details that are easy to miss: the delimiter is a regular expression, and the limit argument changes how empty trailing elements are handled. Understanding both is necessary to avoid subtle bugs.
The split Method and Its Two Signatures
String provides two overloads:
public String[] split(String regex) public String[] split(String regex, int limit)
The one-argument version calls the two-argument version with a limit of 0. That default matters because limit = 0 removes trailing empty strings from the result. For example:
String csv = "a,b,c,"; String[] parts = csv.split(","); System.out.println(parts.length); // 3
The trailing empty element after the final comma is discarded. If you need to preserve it, you must pass a negative limit.
How the Limit Parameter Changes Behavior
The limit parameter controls how many times the pattern is applied and whether trailing empty strings are kept.
- Positive limit: The pattern is applied at most
limit - 1times. The resulting array has at mostlimitelements, and the last element contains the remainder of the string, including any delimiters. - Zero limit: The pattern is applied as many times as possible, but trailing empty strings are removed.
- Negative limit: The pattern is applied as many times as possible, and all trailing empty strings are retained.
Consider the same input with different limits:
String input = "a,b,c,"; System.out.println(Arrays.toString(input.split(",", -1))); // [a, b, c, ] System.out.println(Arrays.toString(input.split(",", 0))); // [a, b, c] System.out.println(Arrays.toString(input.split(",", 2))); // [a, b,c,]
With a limit of 2, the split stops after the first delimiter, so the second element is "b,c,". This is useful when you only need the first few fields and want to avoid scanning the rest of the string.
Regular Expression Behavior and Special Characters
Because the delimiter is a regular expression, characters like ., |, *, +, ?, (, ), [, ], {, }, ^, $, and \ have special meaning. Splitting on a literal dot requires escaping:
String ip = "192.168.0.1"; String[] octets = ip.split("\\."); // correct
Using split(".") would return an empty array because . matches any character, and the split would happen between every pair of characters. The same applies to the pipe character, which is the alternation operator:
String data = "x|y|z"; String[] parts = data.split("\\|"); // correct
If the delimiter is a fixed string without regex metacharacters, Pattern.quote can make the pattern literal:
String delimiter = "."; String[] parts = data.split(Pattern.quote(delimiter));
This avoids manual escaping and keeps the code readable when the delimiter comes from user input or configuration.
Handling Empty Strings and Trailing Empty Elements
Empty strings between consecutive delimiters are preserved, regardless of the limit, as long as they are not trailing and the limit is not positive. For example:
String input = "a,,b"; String[] parts = input.split(","); System.out.println(parts.length); // 3 System.out.println(parts[1].isEmpty()); // true
However, leading empty strings are always kept. The asymmetry only affects trailing empties. If you need to parse a CSV line where trailing commas represent missing values, use a negative limit:
String line = "1,2,,"; String[] fields = line.split(",", -1); System.out.println(fields.length); // 4
The fourth field is an empty string, which correctly represents the missing value.
Performance Considerations: Regex Compilation and Reuse
Every call to String.split compiles the regex pattern internally. If you split many strings with the same delimiter, that repeated compilation adds overhead. For a fixed delimiter, a manual loop using indexOf and substring avoids regex entirely and is often faster for simple cases:
List<String> parts = new ArrayList<>(); int start = 0; int idx; while ((idx = str.indexOf(',', start)) != -1) { parts.add(str.substring(start, idx)); start = idx + 1; } parts.add(str.substring(start));
This approach also gives you full control over trailing empty strings. But it is more verbose and error-prone for complex delimiters.
If you need regex but want to avoid recompilation, precompile a Pattern and use its split method:
Pattern comma = Pattern.compile(","); for (String line : lines) { String[] fields = comma.split(line); // process fields }
The Pattern instance is reused, so the regex is compiled only once. This matters in tight loops or when processing large volumes of text.
Splitting Without Regex for Fixed Delimiters
When the delimiter is a single character or a fixed string, StringTokenizer is an older alternative that does not use regex. It is not deprecated, but it behaves differently: it ignores empty tokens by default and does not support regex. For example:
StringTokenizer st = new StringTokenizer("a,b,c,", ","); while (st.hasMoreTokens()) { System.out.println(st.nextToken()); }
This prints a, b, and c, skipping the trailing empty token. If you need empty tokens, split with a negative limit is clearer. In modern Java, split is generally preferred over StringTokenizer because it returns an array and supports regex, but for very simple fixed delimiters, a manual loop can be more efficient and predictable.
Common Mistakes and Compatibility Notes
One frequent mistake is using split with a regex that matches an empty string. For example, "abc".split("") returns an array with the characters plus a leading empty string in some Java versions. This behavior changed in Java 8: the leading empty string is removed. If you rely on this, test on your target runtime.
Another issue is the limit value interacting with the regex. A positive limit stops splitting early, so the last element may contain delimiters. This is often unexpected when you pass a limit thinking it only caps the array size.
Finally, remember that split returns an empty array if the input string is empty and the regex matches nothing? Actually, "".split(",") returns [""] because the empty string is not split. But "".split(",", -1) also returns [""]. This is consistent with the rule that leading empty strings are kept. For a completely empty input, you get one empty element, not zero.
Understanding these edge cases prevents off-by-one errors and unexpected empty elements. When the delimiter is a regex, always test with representative input, especially if it contains trailing delimiters or consecutive separators.