1. Javaのcontainsを正しく使うための全体像
【結論】containsは「含まれているか」をbooleanで返す便利な判定です。対象がStringかコレクションかで意味と注意点が変わります。
Javaで「入力に禁止語があるか」「リストに指定値が登録済みか」を調べるとき、最初に候補になるのがcontainsです。ただし、部分一致、完全一致、正規表現、大小文字の扱いを混同すると、期待と異なる結果になります。この記事ではString.containsとCollection.containsを分けて、実行・テスト・デバッグまでつながる形で整理します。
1.1 containsが返す値
【結論】一致すればtrue、一致しなければfalseです。見つかった位置や件数は返さないため、必要なら別のAPIを選びます。
String.containsは文字列の一部分を探します。List.containsやSet.containsは、要素が存在するかを調べます。同名でも、比較対象が異なることを先に確認しましょう。

2. String.containsで部分一致を判定する
【結論】String.containsは連続した文字列が含まれるかを判定します。大文字・小文字と空白も比較対象です。
String message = "Java development starts here";
boolean hasJava = message.contains("Java");
boolean hasPython = message.contains("Python");
System.out.println(hasJava); // true
System.out.println(hasPython); // false
2.1 indexOfとの使い分け
【結論】真偽だけが必要ならcontains、位置も必要ならindexOfが読みやすい選択です。
int position = message.indexOf("development");
if (position >= 0) {
System.out.println("開始位置: " + position);
}
indexOfは見つからないと-1を返します。存在確認だけのコードで>= 0を毎回書くより、意図が明確なcontainsを使うと条件式を読み違えにくくなります。
2.2 大文字・小文字を区別しない判定
【結論】containsに大小文字を無視する機能はありません。文字列を正規化して比較します。
import java.util.Locale;
boolean containsJavaIgnoreCase = message
.toLowerCase(Locale.ROOT)
.contains("java");
Locale.ROOTを指定すると、実行環境の既定ロケールに比較結果が左右されにくくなります。ユーザー向け検索では、全角・半角やUnicode正規化まで必要になる場合があるため、要件に合わせて設計してください。
3. null・空文字・正規表現で起きる失敗
【結論】空文字は常に含まれると判定され、nullは例外になります。正規表現はcontainsでは解釈されません。
3.1 nullを安全に扱う
【結論】値がnullになり得るなら、入力境界で検証するか、明示的に条件分岐します。
String keyword = null;
if (keyword != null && message.contains(keyword)) {
System.out.println("見つかりました");
}
次のコードは実行時に失敗します。
message.contains(null);
例外の一例です。
Exception in thread "main" java.lang.NullPointerException
at java.base/java.lang.String.contains(String.java:...)
3.2 空文字と正規表現の違い
【結論】"abc".contains("")はtrueです。また"\d+"は数字パターンではなく文字として探されます。
数字を含むかを調べるなど、正規表現が必要な場合はPatternをコンパイルして使います。
import java.util.regex.Pattern;
Pattern digit = Pattern.compile("\\d+");
boolean hasDigit = digit.matcher("item42").find();
String.matchesは文字列全体がパターンに合うかを判定します。部分一致が必要ならMatcher.find()が適しています。
4. ListとSetのcontainsはequalsで比較する
【結論】コレクションのcontainsは、基本的に要素のequalsで存在を確認します。独自クラスでは実装漏れが原因になりがちです。
import java.util.List;
List<String> languages = List.of("Java", "Kotlin", "Scala");
System.out.println(languages.contains("Java")); // true
4.1 独自クラスで一致しない理由
【結論】別インスタンスでも同じ値として扱いたいなら、equalsとhashCodeを一緒に実装します。
Javaのrecordは値ベースのequalsとhashCodeを自動生成するため、単純なデータを表す用途では安全な選択肢です。
record User(String id, String name) {}
var users = List.of(new User("u-1", "Aki"));
System.out.println(users.contains(new User("u-1", "Aki"))); // true
4.2 ListとSetの選び方
【結論】順番や重複が必要ならList、存在確認を多用し重複を避けたいならSetを検討します。
ArrayList.containsは先頭から比較するため、要素数に応じて時間が増えます。HashSet.containsは適切なhashCodeが実装されている場合、通常は高速に存在確認できます。ただし、順序保証やメモリ使用量の要件も比較してください。
5. コンパイル・実行・テストで確認する
【結論】小さな再現コードをJDKで動かし、境界値をJUnitで固定すると、containsの誤用を早期に見つけられます。
public class ContainsExample {
public static void main(String[] args) {
String text = "error: connection timeout";
System.out.println(text.contains("timeout"));
}
}
javac ContainsExample.java
java ContainsExample
JDKのインストール状況は次で確認できます。
java -version
javac -version
javacが見つからない場合、JREだけではコンパイルできません。使用しているJDKディストリビューションとPATH設定を確認してください。
5.1 MavenとGradleでJUnitを実行する
【結論】既存プロジェクトではビルドツール経由でテストを実行し、依存関係のバージョンはプロジェクトの設定に合わせます。
mvn test
./gradlew test
JUnit 5のテスト例です。
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class ContainsTest {
@Test
void checksExpectedSubstrings() {
String text = "Java 21";
assertTrue(text.contains("Java"));
assertFalse(text.contains("java"));
}
}
6. 期待と違うときのデバッグ手順
【結論】値を引用符付きで出力し、null・空白・大文字小文字・入力文字コードを順に確かめます。
System.out.printf("text=[%s], length=%d%n", text, text.length());
System.out.printf("keyword=[%s], length=%d%n", keyword, keyword.length());
デバッガでは、containsを呼ぶ直前にブレークポイントを置き、textとkeywordの実際の値を確認します。外部ファイルを読むコードでは、文字コードを明示します。
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
String text = Files.readString(Path.of("input.txt"), StandardCharsets.UTF_8);
文字化けしている入力に対してcontainsを実行しても、判定ロジックの問題とは限りません。読み込み時点のバイト列と指定した文字コードを確認するのが近道です。
7. よくある質問
【結論】containsは用途を絞れば単純です。対象の型と比較規則を確認すると、多くのトラブルを防げます。
7.1 String.containsは大文字・小文字を区別しますか?
【結論】はい。String.containsは文字列をそのまま比較するため、Javaとjavaは一致しません。必要ならLocale.ROOTを指定して両方を小文字化してから比較します。
7.2 containsにnullを渡すとどうなりますか?
【結論】String.contains(null)はNullPointerExceptionになります。値がnullになり得るなら、比較前にnullを扱う方針を決めます。
7.3 containsは正規表現を使えますか?
【結論】使えません。正規表現で条件を表したい場合はPatternまたはString.matchesを使います。matchesは文字列全体を判定する点に注意してください。
7.4 List.containsの比較方法は何ですか?
【結論】List.containsは要素のequalsで比較します。独自クラスでは、同一性ではなく値で比較したい場合にequalsとhashCodeを整合させて実装します。
7.5 部分一致で検索するときの文字コードは意識すべきですか?
【結論】Stringの比較自体はUnicodeの文字列に対して行われます。ただし、ファイルやHTTP入力を誤った文字コードで読み込むと、比較前の文字列が壊れるため入出力時のCharset指定が重要です。
7.6 大量データでcontainsが遅いときはどうしますか?
【結論】同じ条件で繰り返し調べるなら、ListではなくHashSetを検討します。順序が必要か、重複を許すかも合わせて選びます。
8. まとめ
【結論】部分一致にはString.contains、要素の存在確認にはコレクションのcontainsを使い分けます。null、大小文字、equals、性能を要件に沿って確認しましょう。
真偽だけで十分か、位置や正規表現が必要かを最初に決めると、API選択が明確になります。まず小さなテストで境界値を確認し、実際の入力・実行環境で再現できる状態を保つことが、安全なJava開発につながります。
