What finding a substring means
Often you need to know where a piece of text sits inside a longer string, or whether it is there at all. Java's String class answers this with indexOf. It returns the position of the first character of the match. Positions are counted from 0, so the first character of a string is at index 0.
String sentence = "Hello World";
int idx = sentence.indexOf("World");
System.out.println(idx); // 6
System.out.println(sentence.indexOf("xyz")); // -1
In "Hello World", the characters at indexes 0 to 4 are Hello, index 5 is the space, and World starts at index 6. When the text isn't there, indexOf returns -1. Because -1 can never be a real position, it works as the "not found" signal. It does not throw an exception.
The variants
s.indexOf(sub)returns the index of the first occurrence ofsub, or-1.s.lastIndexOf(sub)returns the index of the last occurrence, or-1.s.indexOf(sub, fromIdx)starts searching at indexfromIdxinstead of at the beginning.
With "banana", which has the pair an at indexes 1 and 3, they behave like this:
String s = "banana";
System.out.println(s.indexOf("an")); // 1
System.out.println(s.lastIndexOf("an")); // 3
System.out.println(s.indexOf("an", 2)); // 3
System.out.println(s.indexOf("an", 4)); // -1
The last line returns -1 because no an begins at index 4 or later. To visit every match you can keep calling indexOf and start the next search just after the previous hit.
The starting index is forgiving: a negative fromIdx acts like 0, and one at or beyond the length of the string simply finds nothing and returns -1. It never throws an exception, so you can pass pos + 1 without extra checks.
indexOf also accepts a single char: s.indexOf('n') is 2. Note that a character uses single quotes, and a string uses double quotes.
Using the index
An index is most useful when you feed it into other string methods. This loop prints every position where an occurs in "banana", restarting the search one character after each hit:
String text = "banana";
int pos = text.indexOf("an");
while (pos != -1) {
System.out.println("found at " + pos);
pos = text.indexOf("an", pos + 1);
}
// found at 1
// found at 3
The loop ends when indexOf finally returns -1. Here is a second use: splitting an address around the @ with substring:
String email = "ann@mail.com";
int at = email.indexOf("@");
if (at != -1) {
System.out.println(email.substring(0, at)); // ann
System.out.println(email.substring(at + 1)); // mail.com
}
substring(0, at) takes the characters from index 0 up to, but not including, index at. substring(at + 1) takes everything after the @.
The lesson's exercise
The starting code gives one variable:
String sentence = "Hello World";
The task is to find where "World" begins. It takes two small moves:
- Declare an
intnamedidxbelowsentence. Anintis the right type because positions are whole numbers, and it can hold-1as well. - Assign it
sentence.indexOf("World"). The method looks throughsentencefrom the left, findsWorldstarting at index 6 and returns6.
The complete code is:
String sentence = "Hello World";
int idx = sentence.indexOf("World");
Gotchas
- The search is case-sensitive.
sentence.indexOf("world")returns-1, becausewandWare different characters. To ignore case, convert both strings withtoLowerCase()first. - Always allow for -1. Using the result as an index without checking it is a classic bug. If
idxis-1, thensentence.substring(idx)throws aStringIndexOutOfBoundsException. Writeif (idx != -1)first. - Don't test with
> 0. A match at the very start of the string has index 0, which is a valid hit. Useidx >= 0oridx != -1to ask "was it found?". - The index points to the first character, not the end. The match
Worldis 5 characters long, so it occupies indexes 6 to 10. The index just after the match isidx + "World".length(). - If you only need a yes or no, use
contains.sentence.contains("World")returns abooleanand reads more clearly than comparing an index. - An empty search string matches at once.
s.indexOf("")returns0.
Key takeaways
indexOf(sub)returns the start index of the first match and-1when there is none.lastIndexOf(sub)finds the last match, andindexOf(sub, fromIdx)begins the search atfromIdx.- Indexes start at 0, and the search is case-sensitive.
- Check for
-1before using the result as a position.