Substring
Extracting a portion of a string is one of the most common operations in Java, and the substring() method is the primary tool for the job. It lets you “slice” out any section of a String by specifying character positions, and it returns a brand-new String containing only those characters.
The Two Overloads
String.substring() comes in two flavors:
| Method | What It Returns |
|---|---|
substring(int beginIndex) | Characters from beginIndex to the end of the string |
substring(int beginIndex, int endIndex) | Characters from beginIndex up to, but not including, endIndex |
Both are zero-indexed — the first character is at index 0.
String text = "Hello, Java!";
// From index 7 to end
String s1 = text.substring(7);
System.out.println(s1); // Java!
// From index 0 (inclusive) to 5 (exclusive)
String s2 = text.substring(0, 5);
System.out.println(s2); // Hello
Output:
Java!
Hello
Tip: Think of the indexes as pointing between characters, like a cursor position. Index
0is before the first character, index1is after the first character, and so on.substring(2, 5)captures what’s between cursor 2 and cursor 5.
Understanding the Index Rules
The golden rule for substring(beginIndex, endIndex):
beginIndex— inclusive (the character at this position is included)endIndex— exclusive (the character at this position is NOT included)- The resulting string length is always
endIndex - beginIndex
String word = "submarine";
// 012345678
System.out.println(word.substring(0, 3)); // sub (length 3)
System.out.println(word.substring(3, 6)); // mar (length 3)
System.out.println(word.substring(6)); // ine (length 3)
Output:
sub
mar
ine
Edge Cases and Special Behaviors
Extracting the Whole String
Calling substring(0) or substring(0, text.length()) returns a string equal to the original. In Java 7+, it actually returns the same object reference as an optimization in some implementations.
String s = "hello";
String full = s.substring(0);
System.out.println(full.equals(s)); // true
Empty String
If beginIndex == endIndex, you get an empty string — not null, not an error.
String s = "hello";
String empty = s.substring(3, 3);
System.out.println(empty.isEmpty()); // true
System.out.println(empty.length()); // 0
Last N Characters
A handy pattern for extracting the tail of a string:
String filename = "report_2024.pdf";
String extension = filename.substring(filename.length() - 3);
System.out.println(extension); // pdf
StringIndexOutOfBoundsException
If your indexes are out of range, Java throws StringIndexOutOfBoundsException (a subclass of IndexOutOfBoundsException). This is a common runtime bug, so always validate indexes before using them.
Common causes:
| Mistake | Example | Result |
|---|---|---|
beginIndex is negative | s.substring(-1) | Exception |
endIndex > s.length() | s.substring(0, 99) on a 5-char string | Exception |
beginIndex > endIndex | s.substring(5, 2) | Exception |
beginIndex > s.length() | s.substring(10) on a 5-char string | Exception |
String s = "Java";
try {
String bad = s.substring(0, 10); // endIndex > length
} catch (StringIndexOutOfBoundsException e) {
System.out.println("Caught: " + e.getMessage());
}
Output:
Caught: Range [0, 10) out of bounds for length 4
Warning: Always guard dynamic index calculations with bounds checks or wrap in a try-catch when the input is not guaranteed. A simple
if (end <= s.length())check can save you from a crash in production.
Practical Patterns
Removing a Prefix or Suffix
String url = "https://example.com";
// Remove "https://"
if (url.startsWith("https://")) {
String host = url.substring("https://".length());
System.out.println(host); // example.com
}
Extracting Between Two Delimiters
String data = "name=Alice;age=30";
int start = data.indexOf('=') + 1;
int end = data.indexOf(';');
String name = data.substring(start, end);
System.out.println(name); // Alice
Combining with indexOf
indexOf() and substring() are natural partners. You find the position of a separator, then slice around it.
String email = "[email protected]";
int atSign = email.indexOf('@');
String localPart = email.substring(0, atSign); // user
String domainPart = email.substring(atSign + 1); // example.com
System.out.println("User: " + localPart);
System.out.println("Domain: " + domainPart);
Output:
User: user
Domain: example.com
Tip: Java 11 added
stripLeading(),stripTrailing(), andstrip()for whitespace trimming. For more general extraction needs, consider Regular Expressions withMatcher.group().
substring() vs Other Slicing Approaches
| Approach | Use When |
|---|---|
substring(begin, end) | You know exact character positions |
split(regex) | You want to split on a delimiter |
charAt(i) | You need a single character |
String.format() / printf | You’re building a new string from parts |
Pattern / Matcher | Complex pattern-based extraction |
Under the Hood
Java 6: Shared Backing Array (The Old Way)
In Java 6 and earlier, substring() did not copy characters. Instead, it returned a new String object that shared the original’s internal char[] array, using offset and count fields to mark the slice. This was fast to create but caused memory leaks: a tiny substring held a reference to the entire original array, preventing it from being garbage collected.
Java 7u6+: Full Copy (The Current Behavior)
Starting with Java 7 update 6 (and continuing through Java 21), substring() always creates a new, independent copy of the relevant characters. The trade-off:
- No memory leak — the original string can be collected if unreferenced
- Slightly more allocation cost for large strings, but far safer for long-lived code
CharSequence and Interoperability
String implements CharSequence, so substring() results plug directly into APIs that accept CharSequence — like StringBuilder.append(), Pattern.matcher(), and more. You rarely need to wrap the result.
Performance Tip for Heavy Slicing
If you’re extracting many substrings from a large string (e.g., parsing a log file line by line), using a BufferedReader with direct line reads is more efficient than repeated substring() calls on a giant string. For in-memory parsing, consider StringTokenizer or split() for delimiter-based work, or a Scanner for token-based reading (see Scanner).
Quick Reference
String s = "abcdefgh";
// 01234567
s.substring(2); // "cdefgh" — from index 2 to end
s.substring(2, 5); // "cde" — index 2 inclusive to 5 exclusive
s.substring(0, 1); // "a" — just the first character
s.substring(7, 8); // "h" — just the last character
s.substring(0); // "abcdefgh" — full copy
s.substring(4, 4); // "" — empty string
Related Topics
- String Methods — full reference for all built-in
Stringmethods includingindexOf,replace, andtrim - Strings — start here for a complete overview of how Strings work in Java
- String Comparison — how to compare strings correctly with
equals()andcompareTo() - Regular Expressions — powerful pattern-based extraction when
substring()isn’t enough - StringBuffer and StringBuilder — mutable alternatives when you need to build or modify strings efficiently
- StringTokenizer — a lightweight alternative for splitting strings by delimiter