W3docs

How to Check if a String Contains a Substring in Java

Check for a substring in a Java string with contains, indexOf, startsWith, endsWith, and regex.

How to Check if a String Contains a Substring in Java

Checking whether one String appears inside another is one of the most common text tasks in Java. The right tool depends on what you actually need: a plain yes/no answer, the position of the match, an anchored check at the start or end, or a flexible pattern. This chapter walks through each idiomatic approach and when to reach for it.

The default: String.contains

When you only need a boolean — "is this fragment in there or not?" — contains is the clearest choice:

String text = "The quick brown fox";
boolean hasFox = text.contains("fox");   // true
boolean hasCat = text.contains("cat");   // false

contains accepts any CharSequence (so String, StringBuilder, etc.) and returns true if the argument occurs anywhere in the string. It is case-sensitive: text.contains("FOX") is false. One edge case worth remembering — the empty string is contained in every string, so text.contains("") is always true.

When you need the position: indexOf

contains is actually implemented on top of indexOf. If you need to know where a match starts (or want to scan for repeats), call indexOf directly:

String text = "The quick brown fox";
int at = text.indexOf("brown");   // 10
int no = text.indexOf("bird");    // -1

indexOf returns the zero-based index of the first match, or -1 when the substring is absent. The classic membership idiom is text.indexOf("brown") >= 0, which is equivalent to contains but also hands you the position for free. There is also lastIndexOf for searching from the end, and an overload that takes a starting offset for finding subsequent matches in a loop.

Anchored checks: startsWith and endsWith

If you specifically care about the beginning or end of a string — file extensions, URL prefixes, protocol schemes — startsWith and endsWith express the intent directly and read better than slicing:

String file = "report.pdf";
boolean isPdf  = file.endsWith(".pdf");      // true
boolean isHttp = "https://w3docs.com".startsWith("https://"); // true

These are faster and clearer than indexOf(prefix) == 0, because they stop comparing as soon as a character differs and never scan the whole string.

Case-insensitive and pattern matching

contains has no case-insensitive overload. The simplest fix is to normalise both sides:

boolean ci = text.toLowerCase().contains("FOX".toLowerCase()); // true

For more than a literal fragment — alternatives, wildcards, word boundaries — use a regular expression. Pattern.compile(...).matcher(text).find() returns true if the pattern matches anywhere, and CASE_INSENSITIVE handles casing without allocating lowercase copies:

import java.util.regex.Pattern;
boolean found = Pattern.compile("fox", Pattern.CASE_INSENSITIVE)
                       .matcher(text).find();
ApproachReturnsUse when
containsbooleanPlain membership, literal text
indexOfint (position, or -1)You need where the match is
startsWith / endsWithbooleanAnchored at start or end
Pattern.findbooleanPatterns, alternatives, case-insensitive

A worked example

This program runs the four approaches side by side over one sentence, including the case-sensitivity gotcha and the empty-string edge case.

java— editable, runs on the server

What to take from the run:

  • contains "brown" prints true and contains "cat" prints falsecontains is the direct boolean membership test for literal text.
  • contains "FOX" prints false even though the word "fox" is present, proving contains is case-sensitive; the normalised contains "FOX" (ci) line prints true.
  • indexOf "fox" prints 16, the zero-based start position of the match, while indexOf "bird" prints -1 to signal "not found" — that -1 is the sentinel you test against.
  • startsWith "The" and endsWith "dog" both print true, showing the anchored checks reading the very start and very end of the sentence.
  • contains "" prints true, the reminder that every string contains the empty string — guard against empty inputs if that would be a bug.

Practice

Practice

What does text.indexOf('bird') return when 'bird' is not present in the string text?