Mastering contains() in Java: How to Perform Efficient Substring Searches

目次

1. Introduction: Why String Search Matters in Java

String manipulation is one of the most frequently used operations when programming in Java. Whether checking user input, parsing file contents, or searching for specific keywords, you often need to determine whether a particular word is contained within a given string. To meet these needs, Java provides a convenient method called contains(). With this method, you can easily determine whether one string partially contains another. For example, if you want to check whether an error message contains a specific keyword, contains() allows you to do so in a single line of code. Especially in scenarios involving large volumes of text—such as web applications, API processing, or log analysis—the contains() method greatly improves code readability and maintainability. However, there are also important considerations such as case sensitivity and the possibility of null. This article explains Java’s contains() method in detail—from basic usage and common mistakes to differences from other methods and practical applications. Our goal is to provide useful information not only for beginners but also for developers actively using Java in real-world projects.

2. Basic Syntax and Characteristics of the contains() Method

Java’s contains() method determines whether a string partially contains another string. Its syntax is very simple, yet it is highly practical and used frequently in everyday programming tasks.

Basic Syntax

boolean result = targetString.contains(searchString);
The method belongs to the String class and accepts a CharSequence (commonly a String) as its argument. Its return value is boolean: true if the target string contains the given substring, and false otherwise.

Sample Code

String message = "Java programming is fun!";
boolean hasKeyword = message.contains("programming");

System.out.println(hasKeyword); // Output: true
In the example above, the substring "programming" is present in the target string, so contains() returns true.

Characteristics of the Method

  • Checks only for partial match: If you need an exact match, use equals() instead.
  • Case-sensitive: For example, "Java" and "java" are treated as different (details explained later).
  • Does not support regular expressions: Because it simply checks for the presence of a string, pattern matching requires matches() or the Pattern class.

Behavior When null Is Passed

Passing null to contains() triggers a NullPointerException. For example, the following code will throw an exception:
String text = null;
System.out.println(text.contains("test")); // Exception occurs
Likewise, if the target string itself is null, the same exception will be thrown. Therefore, it is highly recommended to perform null checks before calling contains().

3. Practical Usage Examples and Important Considerations

Java’s contains() method is very intuitive and convenient, but incorrect usage can lead to unexpected bugs or inefficient code. This section explains the basic usage of contains() along with key points you should be aware of.

3-1. Basic Usage Example

The following code demonstrates a simple example of checking whether the target string contains a specific keyword:
String sentence = "今日はJavaの勉強をしています。";

if (sentence.contains("Java")) {
    System.out.println("Javaが含まれています。");
} else {
    System.out.println("Javaは含まれていません。");
}
As shown, contains() is frequently combined with if statements to perform conditional branching.

3-2. Case Sensitivity

The contains() method is case-sensitive. For example, the following code returns false:
String text = "Welcome to Java";
System.out.println(text.contains("java")); // false
In such cases, it is common to convert the strings to lowercase (or uppercase) before comparison:
String text = "Welcome to Java";
System.out.println(text.toLowerCase().contains("java")); // true
This approach helps eliminate differences in input case (e.g., user input).

3-3. Handling of null and Empty Strings

One of the most important considerations when using contains() is the handling of null. If either the target string or the argument is null, a NullPointerException will occur.
String text = null;
System.out.println(text.contains("test")); // Runtime error
To avoid this issue, always add a null check:
if (text != null && text.contains("test")) {
    // Safe to process
}
Also note: Passing an empty string ("") always returns true.
String sample = "test";
System.out.println(sample.contains("")); // true
However, this behavior is rarely useful in practice and can unintentionally lead to bugs if empty strings are passed unintentionally.

3-4. Does Not Support Multiple Keyword Searches

contains() can check only one keyword at a time. To check multiple keywords, you must either call contains() multiple times or use the Stream API.
String target = "エラーコード123:アクセス拒否";
if (target.contains("エラー") || target.contains("拒否")) {
    System.out.println("問題のあるメッセージです。");
}
Or, for dynamic keyword sets:
List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(target::contains);

4. Methods Frequently Compared with contains()

Java provides several methods for comparing strings or checking whether a specific substring exists. Among them, contains() is used for “partial match,” but other methods also serve similar purposes. This section explains the characteristics and differences of those methods to help you use them appropriately.

4-1. Difference from equals(): Exact Match vs. Partial Match

equals() determines whether two strings are exactly identical. In contrast, contains() checks for partial matches.
String a = "Java";
String b = "Java";

System.out.println(a.equals(b));      // true: Exact match
System.out.println(a.contains("av")); // true: Partial match
Main differences:
Comparisonequals()contains()
Match TypeExact matchPartial match
Case SensitivitySensitiveSensitive
Argument TypeObjectCharSequence
Usage Guideline: Use equals() when values must match exactly (e.g., ID verification). Use contains() when partial matches are acceptable (e.g., keyword search).

4-2. Difference from indexOf(): Whether You Need the Position

The indexOf() method can also be used to check whether a substring exists within a string. The difference is that indexOf() returns the starting index of the substring if found. If the substring is not found, it returns -1.
String text = "Hello, Java World!";
System.out.println(text.indexOf("Java"));    // 7
System.out.println(text.indexOf("Python"));  // -1
You can also use indexOf() to replicate the behavior of contains():
if (text.indexOf("Java") >= 0) {
    System.out.println("It is contained.");
}
Usage guideline: If you don’t need the index, contains() is more readable and preferable.

4-3. Difference from matches(): Support for Regular Expressions

The matches() method checks whether a string fully matches a given regular expression. In contrast, contains() checks only for literal substring matches and does not support regex.
String text = "abc123";
System.out.println(text.matches(".*123")); // true
System.out.println(text.contains(".*123")); // false (not regex)
If you want regex-based partial matching, use the Pattern class:

4-4. Summary of Feature Comparison

MethodPurposeReturn TypeRegex SupportUse Case
contains()Partial matchbooleanNoKeyword search
equals()Exact matchbooleanNoID/password checks
indexOf()Get match positionintNoIndex-based processing
matches()Regex matchbooleanYesFind pattern-based strings

5. Common Use Cases and Sample Code

Java’s contains() method is simple yet widely used in real development scenarios. Typical use cases include user input validation, log analysis, and filtering operations. This section covers practical examples with corresponding code.

5-1. User Input Validation (Detecting Prohibited Words)

In forms or chat applications, you may need to detect whether certain prohibited words are included.
String input = "このアプリは最悪だ";
String banned = "最悪";

if (input.contains(banned)) {
    System.out.println("不適切な言葉が含まれています。");
}
Handling multiple NG words:
List<String> bannedWords = Arrays.asList("最悪", "バカ", "死ね");
for (String word : bannedWords) {
    if (input.contains(word)) {
        System.out.println("不適切な言葉が含まれています: " + word);
        break;
    }
}

5-2. Log File Analysis (Detecting Specific Messages)

When analyzing system or application logs, you may want to extract only lines containing specific keywords like ERROR or WARN.
List<String> logs = Arrays.asList(
    "[INFO] サーバーが起動しました",
    "[ERROR] データベース接続失敗",
    "[WARN] メモリ使用率が高い"
);

for (String log : logs) {
    if (log.contains("ERROR")) {
        System.out.println("エラー発生ログ: " + log);
    }
}

5-3. Filtering Strings in a List (Using Stream API)

When handling large datasets, use the Stream API to extract only elements containing a specific substring:
List<String> users = Arrays.asList("tanaka@example.com", "sato@gmail.com", "yamada@yahoo.co.jp");

List<String> gmailUsers = users.stream()
    .filter(email -> email.contains("@gmail.com"))
    .collect(Collectors.toList());

System.out.println(gmailUsers); // [sato@gmail.com]

5-4. Parsing HTTP Request Headers or URLs

In web development, routing or device-specific handling may require checking substrings in the User-Agent or URL.
String userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)";
if (userAgent.contains("iPhone")) {
    System.out.println("スマートフォンからのアクセスです。");
}

5-5. Checking File Paths or Extensions

To determine the type of a file using its path:
String filePath = "/usr/local/data/sample.csv";
if (filePath.contains(".csv")) {
    System.out.println("CSVファイルです。");
}
Note: For file extension checks, endsWith(".csv") is often more accurate.

Practical Considerations

  • Apply normalization (e.g., toLowerCase(), trim()) when accuracy is required.
  • For large-scale data, consider Stream API or regex.
  • Remember that contains() is partial match—combine with other conditions for safer logic.

6. Performance Considerations

While the contains() method offers excellent readability and simplicity, you must consider its performance impact when handling large datasets or running repeated operations. This section explains the processing cost of contains() and alternative approaches for improved efficiency.

6-1. Internal Behavior and Time Complexity of contains()

The contains() method searches the target string sequentially from the beginning to locate the substring. Internally, it relies on the indexOf() method, and its worst-case time complexity is: O(n * m) – n = length of the target string – m = length of the search string Example of heavy processing:
for (String line : hugeTextList) {
    if (line.contains("error")) {
        // processing
    }
}
This can significantly affect performance when repeated within large loops.

6-2. Techniques for Improving Performance During Frequent Searches

When using contains() repeatedly in large datasets, the following techniques can improve processing speed:
• Convert all strings to lowercase in advance
Instead of calling toLowerCase() during each comparison, normalize the strings beforehand:
List<String> normalizedList = originalList.stream()
    .map(String::toLowerCase)
    .collect(Collectors.toList());
• Use Stream API with parallel() for parallel processing
Utilize CPU cores to speed up searches:
List<String> result = hugeTextList.parallelStream()
    .filter(line -> line.contains("keyword"))
    .collect(Collectors.toList());
• Use regular expressions for complex search patterns
If the conditions are complex and can be expressed in one regex, Pattern may perform better:
Pattern pattern = Pattern.compile("error|fail|fatal");
for (String log : logs) {
    if (pattern.matcher(log).find()) {
        // matched
    }
}

6-3. Memory Efficiency and Reusability Considerations

Operations that frequently convert strings—such as toLowerCase() or substring()—may generate many unnecessary string objects, affecting memory usage. This is particularly important for long-running applications or server-side processing. Key points:
  • Avoid creating unnecessary string instances.
  • For large datasets, consider buffering or chunk processing.
  • Caching repeated contains() results may improve performance in certain cases.

7. Comparison with Other Programming Languages

Java’s contains() method offers simple, reliable substring matching, but other languages provide similar features with their own characteristics. This section compares substring checking in Python, JavaScript, and C# to highlight differences and similarities.

7-1. Python: Simple Partial Match with the in Operator

In Python, you can check substring inclusion using the in operator:
text = "Hello, Python!"
if "Python" in text:
    print("含まれています")
This syntax is extremely readable—almost like natural language—and requires minimal learning. Differences and Notes:
  • in is a language operator, not a method.
  • Python is also case-sensitive for string comparison.
  • None produces an exception; null checks are required.

7-2. JavaScript: Partial Match with includes()

In JavaScript (ES6+), you can use the includes() method:
const text = "JavaScript is fun";
console.log(text.includes("fun")); // true
This method is very similar to Java’s contains() and easy to migrate mentally. Differences and Notes:
  • Passing undefined does not throw an exception; it simply returns false.
  • includes() also works on arrays, increasing its versatility.

7-3. C#: Contains() Similar to Java

C# also offers a Contains() method with behavior similar to Java:
string text = "Welcome to C#";
bool result = text.Contains("C#");
Differences and Notes:
  • C# Contains() is case-sensitive by default, but you can ignore case using StringComparison.OrdinalIgnoreCase.
  • Passing null triggers ArgumentNullException.

7-4. Comparison Table Across Languages

LanguageExample SyntaxCase SensitivityNotes
Java"abc".contains("a")SensitiveThrows exception on null
Python"a" in "abc"SensitiveMost intuitive syntax
JavaScript"abc".includes("a")SensitiveAlso works for arrays
C#"abc".Contains("a")Sensitive (configurable)Comparison mode can be chosen

Summary: Choose the Right Syntax for Your Use Case

Although substring checking is a common requirement across languages, each language provides its own method or syntax. Java’s contains() offers stability and clarity, making it well-suited for enterprise systems and maintainable applications. Languages like Python and JavaScript offer simpler and more concise syntax, which can be ideal for lightweight scripts or rapid prototyping. By understanding both the common concepts and the specific features of each language, you’ll be able to write safer and more efficient code across various languages.

8. Frequently Asked Questions (FAQ)

Below are commonly asked questions regarding Java’s contains() method—helping you understand tricky points and avoid common pitfalls.

Q1. Is contains() case-sensitive?

Yes, it is case-sensitive. For example, "Java".contains("java") returns false. Solution:
String input = "Welcome to Java";
boolean result = input.toLowerCase().contains("java");

Q2. How can I check partial matches using regular expressions?

contains() does not support regular expressions. Use matches() or the Pattern class instead. Example (checking numeric pattern):
import java.util.regex.Pattern;
import java.util.regex.Matcher;

String text = "注文番号: A123456";
Pattern pattern = Pattern.compile("A\\d+");
Matcher matcher = pattern.matcher(text);

if (matcher.find()) {
    System.out.println("パターンに一致しました。");
}

Q3. What happens if I call contains() on null?

A NullPointerException will be thrown.
String target = null;
System.out.println(target.contains("test")); // Error
Solution:
if (target != null && target.contains("test")) {
    System.out.println("含まれています。");
}

Q4. What happens if I pass an empty string (“”) to contains()?

It always returns true.
String text = "Java";
System.out.println(text.contains("")); // true
Although part of the official specification, this behavior is rarely useful and may cause unexpected bugs if empty strings are not intended.

Q5. Can contains() search multiple keywords at once?

No. Each call checks only one keyword.
String text = "本日はシステムエラーが発生しました";
if (text.contains("エラー") || text.contains("障害") || text.contains("失敗")) {
    System.out.println("問題が検出されました。");
}
Dynamic approach:
List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(text::contains);

Q6. When should I use contains() vs indexOf()?

contains() returns a boolean, while indexOf() returns a numeric index.
  • Use contains() when you simply want to know if the substring exists.
  • Use indexOf() when you also need the position.
String text = "Error: Disk full";
if (text.contains("Error")) {
    int pos = text.indexOf("Error");
    System.out.println("Position: " + pos);
}

9. Conclusion

Java’s contains() method is a powerful and convenient tool for determining whether a specific substring is contained within a string. It is widely used across various scenarios such as user input validation, log analysis, and data filtering. In this article, we covered:
  • Basic syntax and return values
  • Case sensitivity and how to handle it
  • Handling nulls and empty strings
  • Differences from other string comparison methods
  • Practical use cases: validation, log search, Stream processing
  • Performance considerations and optimization techniques
  • Comparison with Python, JavaScript, and C#
  • Frequently asked questions and troubleshooting tips
Although contains() is intuitive and versatile, its use should be carefully evaluated in cases involving large datasets, frequent calls, or complex search conditions. By combining normalization, parallel processing, regex, and caching strategies, you can maintain both performance and readability. Since contains() is fundamental to working with strings in Java, we hope this article helps you use it more safely and effectively in your development projects.