Searching inside text is one of the most common operations in Java applications. Whether you are checking a username, looking for a keyword in a document, validating a file name, locating a symbol in an expression, or processing data received from an API, you often need to answer one simple question: “Does this text contain what I am looking for?”
Java's String class provides several methods for searching text. The most useful ones include contains(), indexOf(), lastIndexOf(), startsWith(), and endsWith().
Why String Searching Matters
Consider a search box in an online store. A customer types laptop, and the application needs to determine whether product descriptions contain that word. Or imagine a log-processing application looking for ERROR messages. These are string-searching problems.
The good news is that Java provides direct methods for many of these tasks, so you do not need to manually inspect every character for simple searches.
contains()
The contains() method checks whether a string contains a specified sequence of characters. It returns either true or false.
String message = "Welcome to Java Programming";
System.out.println(message.contains("Java"));
System.out.println(message.contains("Python"));
Output:
true false
This is often the simplest choice when you only care whether some text exists and do not need to know its position.
Use contains() when the question is simply: “Does this string contain this text?”
contains() Is Case-Sensitive
String searching with contains() is case-sensitive.
String message = "Welcome to Java";
System.out.println(message.contains("Java"));
System.out.println(message.contains("java"));
The output is:
true false
If your application should treat uppercase and lowercase letters as equivalent, you must deliberately normalize the data or use another appropriate comparison strategy.
Case-Insensitive Searching
Java's String class does not provide a direct containsIgnoreCase() method. A common approach is to normalize both strings before searching.
String message = "Welcome to Java"; String search = "java"; boolean found = message.toLowerCase().contains(search.toLowerCase()); System.out.println(found);
Output:
true
For locale-sensitive applications, blindly converting text to lowercase can have linguistic implications. In production systems, choose a comparison strategy appropriate for the language and business requirement.
indexOf()
When you need to know where a character or sequence occurs, use indexOf().
String message = "Java Programming";
int position = message.indexOf("Java");
System.out.println(position);
Output:
0
The result is 0 because Java begins at index zero.
Searching for a Character
The indexOf() method can search for an individual character as well.
String language = "Java";
System.out.println(language.indexOf('v'));
System.out.println(language.indexOf('a'));
Output:
2 1
Notice the use of single quotes for individual characters and double quotes for strings.
Searching for Text That Does Not Exist
If indexOf() cannot find the requested character or sequence, it returns -1.
String message = "Java Programming";
int position = message.indexOf("Python");
System.out.println(position);
Output:
-1
This return value is extremely useful in conditional logic.
String message = "Java Programming";
if (message.indexOf("Java") != -1) {
System.out.println("Java was found");
}
The condition succeeds because Java exists in the string.
Never assume that indexOf() always returns a valid position. A return value of -1 means that the searched value was not found.
lastIndexOf()
When text appears multiple times, lastIndexOf() finds the position of the final occurrence.
String text = "Java is powerful. Java is popular.";
System.out.println(text.indexOf("Java"));
System.out.println(text.lastIndexOf("Java"));
The first method finds the first Java, while the second finds the last one.
This is especially useful when working with file paths, extensions, repeated delimiters, or text containing multiple occurrences of the same value.
Finding a File Extension
A practical example of lastIndexOf() is locating the final dot in a file name.
String fileName = "report.final.pdf";
int dot = fileName.lastIndexOf('.');
System.out.println(dot);
The last dot is important because the file name itself may contain other dots. Searching from the end helps identify the final extension separator.
startsWith()
The startsWith() method checks whether a string begins with a specified sequence.
String url = "https://example.com";
System.out.println(url.startsWith("https"));
System.out.println(url.startsWith("ftp"));
Output:
true false
This is useful for checking prefixes such as URL schemes, command names, file-name prefixes, product codes, and application-specific identifiers.
startsWith() with an Offset
Java also provides an overloaded version of startsWith() that allows you to specify the position from which the check should begin.
String text = "Java Programming";
System.out.println(text.startsWith("Programming", 5));
Output:
true
Here, Java begins the prefix check at index 5, where Programming begins.
endsWith()
The endsWith() method checks whether a string ends with a specified sequence.
String fileName = "invoice.pdf";
System.out.println(fileName.endsWith(".pdf"));
System.out.println(fileName.endsWith(".txt"));
Output:
true false
This method is useful when checking file extensions, URL suffixes, identifiers, and other values with meaningful endings.
Searching with a Loop
Built-in methods are ideal for straightforward searches, but sometimes your application needs to inspect characters individually. In that situation, a loop combined with charAt() can be useful.
String text = "Java";
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == 'v') {
System.out.println("Found at index: " + i);
}
}
Output:
Found at index: 2
This approach gives you more control, such as counting occurrences, applying custom conditions, or performing special processing for each matching character.
Counting Occurrences
Suppose you want to count how many times a particular character appears. A loop gives you direct control over the search.
String text = "banana";
int count = 0;
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == 'a') {
count++;
}
}
System.out.println(count);
Output:
3
For more advanced searching and pattern matching, Java also provides regular-expression support through classes such as Pattern and Matcher. Those tools are useful when the search rules are more complex than a simple substring or character lookup.
Searching from a Specific Position
The overloaded indexOf() method can begin searching from a specified index.
String text = "Java Java Java";
int first = text.indexOf("Java");
int second = text.indexOf("Java", first + 1);
System.out.println(first);
System.out.println(second);
This technique is useful when you need to locate multiple occurrences rather than stopping at the first match.
Searching for Multiple Occurrences
You can repeatedly use indexOf() to find every occurrence of a sequence.
String text = "Java Java Java";
String target = "Java";
int position = text.indexOf(target);
while (position != -1) {
System.out.println("Found at: " + position);
position = text.indexOf(target, position + target.length());
}
This pattern continues searching after each match until indexOf() returns -1.
Searching Does Not Modify the String
Search methods only inspect the String. They do not change its contents.
String message = "Java Programming";
message.contains("Java");
message.indexOf("Programming");
System.out.println(message);
The original value remains:
Java Programming
This follows directly from String immutability.
Choosing the Right Search Method
| Method | Question It Answers | Result |
|---|---|---|
| contains() | Does this text exist anywhere? | boolean |
| indexOf() | Where is the first occurrence? | int |
| lastIndexOf() | Where is the last occurrence? | int |
| startsWith() | Does the text begin with this value? | boolean |
| endsWith() | Does the text end with this value? | boolean |
| charAt() | What character exists at this position? | char |
| Pattern / Matcher | Does complex text match a pattern? | Pattern matching result |
Common Beginner Mistakes
- Forgetting that String searches are case-sensitive by default.
- Treating -1 from indexOf() as a valid character position.
- Using indexOf() when only a simple true-or-false check is required.
- Forgetting that lastIndexOf() finds the final occurrence, not the first.
- Using startsWith() or endsWith() when the desired text may occur anywhere in the string.
- Using manual loops for simple searches that could be expressed clearly with built-in String methods.
- Assuming search methods modify the original String.
Best Practices
- Use contains() when you only need to know whether text exists.
- Use indexOf() when the position of a match matters.
- Use lastIndexOf() when the final occurrence is important.
- Use startsWith() and endsWith() for prefix and suffix validation.
- Normalize input deliberately when searches should ignore case or irrelevant whitespace.
- Use regular expressions only when the search requirement genuinely involves patterns; simple String methods are usually easier to read.
- Check the return value of index-based searches before using it as an index for another operation.
Quick Learning Checkpoint
Consider this string:
String text = "Java makes Java development enjoyable";
Before running the code, try to predict what each operation tells you:
text.contains("Java");
text.indexOf("Java");
text.lastIndexOf("Java");
text.startsWith("Java");
text.endsWith("enjoyable");
If you can immediately identify which methods return a boolean and which return an index, you have the core idea of String searching under control.
Interview Insight
A common interview exercise asks you to find the first or last occurrence of a character or word. Know the difference between contains(), indexOf(), and lastIndexOf(). Also remember the special -1 result from indexOf(). Interviewers may then extend the problem by asking you to find every occurrence, count matches, or perform a case-insensitive search.
String Searching at a Glance
| Requirement | Recommended Approach | Key Detail |
|---|---|---|
| Check whether text exists | contains() | Returns true or false |
| Find first occurrence | indexOf() | Returns index or -1 |
| Find final occurrence | lastIndexOf() | Searches from the end |
| Check prefix | startsWith() | Checks the beginning |
| Check suffix | endsWith() | Checks the ending |
| Inspect characters | charAt() | Uses zero-based indexes |
| Complex pattern search | Pattern and Matcher | Uses regular expressions |
Final Takeaway
Java provides several clean ways to search strings, and choosing the right method makes your code both shorter and clearer. Use contains() for a simple existence check, indexOf() and lastIndexOf() when position matters, and startsWith() or endsWith() for prefix and suffix checks. When searching becomes more complex, regular expressions can take over. Once you know how to locate text reliably, the next natural step is learning how to take a selected portion of that text—String Extraction.
