Maîtriser contains() en Java : comment effectuer des recherches de sous‑chaînes efficaces

目次

1. Introduction : Pourquoi la recherche de chaînes est importante en Java

La manipulation de chaînes est l’une des opérations les plus fréquemment utilisées lors de la programmation en Java.
Que ce soit pour vérifier l’entrée utilisateur, analyser le contenu d’un fichier ou rechercher des mots‑clés spécifiques, il faut souvent déterminer si un mot particulier est présent dans une chaîne donnée.

Pour répondre à ces besoins, Java fournit une méthode pratique appelée contains().
Avec cette méthode, vous pouvez facilement déterminer si une chaîne contient partiellement une autre.
Par exemple, si vous souhaitez vérifier si un message d’erreur contient un mot‑clé spécifique, contains() vous permet de le faire en une seule ligne de code.

Surtout dans les scénarios impliquant de grands volumes de texte — comme les applications web, le traitement d’API ou l’analyse de journaux — la méthode contains() améliore considérablement la lisibilité et la maintenabilité du code.
Cependant, il existe également des considérations importantes telles que la sensibilité à la casse et la possibilité de null.

Cet article explique en détail la méthode contains() de Java — de l’utilisation de base et des erreurs courantes aux différences avec d’autres méthodes et aux applications pratiques.
Notre objectif est de fournir des informations utiles non seulement aux débutants, mais aussi aux développeurs qui utilisent Java dans des projets réels.

2. Syntaxe de base et caractéristiques de la méthode contains()

La méthode contains() de Java détermine si une chaîne contient partiellement une autre chaîne.
Sa syntaxe est très simple, mais elle est très pratique et utilisée fréquemment dans les tâches de programmation quotidiennes.

Syntaxe de base

boolean result = targetString.contains(searchString);

La méthode appartient à la classe String et accepte un CharSequence (généralement un String) comme argument.
Sa valeur de retour est boolean : true si la chaîne cible contient la sous‑chaîne donnée, et false sinon.

Exemple de code

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

System.out.println(hasKeyword); // Output: true

Dans l’exemple ci‑dessus, la sous‑chaîne "programming" est présente dans la chaîne cible, donc contains() renvoie true.

Caractéristiques de la méthode

  • Vérifie uniquement une correspondance partielle : Si vous avez besoin d’une correspondance exacte, utilisez equals() à la place.
  • Sensible à la casse : Par exemple, "Java" et "java" sont considérés comme différents (détails expliqués plus tard).
  • Ne supporte pas les expressions régulières : Parce qu’elle se contente de vérifier la présence d’une chaîne, le filtrage par motif nécessite matches() ou la classe Pattern.

Comportement lorsqu’un null est passé

Passer null à contains() déclenche une NullPointerException.
Par exemple, le code suivant lèvera une exception :

String text = null;
System.out.println(text.contains("test")); // Exception occurs

De même, si la chaîne cible elle‑même est null, la même exception sera levée.
Par conséquent, il est fortement recommandé d’effectuer des vérifications de nullité avant d’appeler contains().

3. Exemples d’utilisation pratique et considérations importantes

La méthode contains() de Java est très intuitive et pratique, mais une mauvaise utilisation peut entraîner des bugs inattendus ou un code inefficace.
Cette section explique l’utilisation de base de contains() ainsi que les points clés dont vous devez être conscient.

3-1. Exemple d’utilisation de base

Le code suivant montre un exemple simple de vérification si la chaîne cible contient un mot‑clé spécifique :

String sentence = "今日はJavaの勉強をしています。";

if (sentence.contains("Java")) {
    System.out.println("Javaが含まれています。");
} else {
    System.out.println("Javaは含まれていません。");
}

Comme le montre l’exemple, contains() est fréquemment combiné avec des instructions if pour effectuer un branchement conditionnel.

3-2. Sensibilité à la casse

La méthode contains() est sensible à la casse.
Par exemple, le code suivant renvoie false :

String text = "Welcome to Java";
System.out.println(text.contains("java")); // false

Dans de tels cas, il est courant de convertir les chaînes en minuscules (ou en majuscules) avant la comparaison :

String text = "Welcome to Java";
System.out.println(text.toLowerCase().contains("java")); // true

Cette approche aide à éliminer les différences de casse dans l’entrée (par exemple, la saisie de l’utilisateur).

3-3. Gestion du null et des chaînes vides

L’une des considérations les plus importantes lors de l’utilisation de contains() est la gestion du null.
Si la chaîne cible ou l’argument est null, une NullPointerException se produira.

String text = null;
System.out.println(text.contains("test")); // Runtime error

Pour éviter ce problème, ajoutez toujours une vérification de null :

if (text != null && text.contains("test")) {
    // Safe to process
}

À noter également :
Passer une chaîne vide ("") renvoie toujours true.

String sample = "test";
System.out.println(sample.contains("")); // true

Cependant, ce comportement est rarement utile en pratique et peut entraîner involontairement des bugs si des chaînes vides sont passées par inadvertance.

3-4. Ne prend pas en charge les recherches de plusieurs mots-clés

contains() ne peut vérifier qu’un seul mot-clé à la fois.
Pour vérifier plusieurs mots-clés, vous devez soit appeler contains() plusieurs fois, soit utiliser l’API Stream.

String target = "エラーコード123:アクセス拒否";
if (target.contains("エラー") || target.contains("拒否")) {
    System.out.println("問題のあるメッセージです。");
}

Ou, pour des ensembles de mots-clés dynamiques :

List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(target::contains);

4. Méthodes souvent comparées à contains()

Java propose plusieurs méthodes pour comparer des chaînes ou vérifier si une sous-chaîne spécifique existe.
Parmi elles, contains() est utilisé pour une « correspondance partielle », mais d’autres méthodes remplissent également des fonctions similaires.
Cette section explique les caractéristiques et les différences de ces méthodes afin de vous aider à les utiliser correctement.

4-1. Différence avec equals() : correspondance exacte vs. correspondance partielle

equals() détermine si deux chaînes sont exactement identiques.
En revanche, contains() vérifie les correspondances partielles.

String a = "Java";
String b = "Java";

System.out.println(a.equals(b));      // true: Exact match
System.out.println(a.contains("av")); // true: Partial match

Principales différences :

Comparisonequals()contains()
Match TypeExact matchPartial match
Case SensitivitySensitiveSensitive
Argument TypeObjectCharSequence

Guide d’utilisation :
Utilisez equals() lorsque les valeurs doivent correspondre exactement (par exemple, vérification d’ID).
Utilisez contains() lorsque les correspondances partielles sont acceptables (par exemple, recherche de mots-clés).

4-2. Différence avec indexOf() : besoin ou non de la position

La méthode indexOf() peut également être utilisée pour vérifier si une sous-chaîne existe dans une chaîne.
La différence est que indexOf() renvoie l’indice de départ de la sous-chaîne si elle est trouvée.
Si la sous-chaîne n’est pas trouvée, elle renvoie -1.

String text = "Hello, Java World!";
System.out.println(text.indexOf("Java"));    // 7
System.out.println(text.indexOf("Python"));  // -1

Vous pouvez également utiliser indexOf() pour reproduire le comportement de contains() :

if (text.indexOf("Java") >= 0) {
    System.out.println("It is contained.");
}

Guide d’utilisation :
Si vous n’avez pas besoin de l’indice, contains() est plus lisible et préférable.

4-3. Différence avec matches() : prise en charge des expressions régulières

La méthode matches() vérifie si une chaîne correspond entièrement à une expression régulière donnée.
En revanche, contains() ne vérifie que les correspondances de sous-chaînes littérales et ne prend pas en charge les regex.

String text = "abc123";
System.out.println(text.matches(".*123")); // true
System.out.println(text.contains(".*123")); // false (not regex)

Si vous souhaitez une correspondance partielle basée sur les expressions régulières, utilisez la classe Pattern :

4-4. Résumé de la comparaison des fonctionnalités

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. Cas d’utilisation courants et code d’exemple

Java contains() est simple mais largement utilisée dans les scénarios de développement réels.
Les cas d’utilisation typiques incluent la validation d’entrée utilisateur, l’analyse de journaux et les opérations de filtrage.
Cette section couvre des exemples pratiques avec le code correspondant.

5-1. Validation d’entrée utilisateur (détection de mots interdits)

Dans les formulaires ou les applications de chat, il peut être nécessaire de détecter si certains mots interdits sont présents.

String input = "このアプリは最悪だ";
String banned = "最悪";

if (input.contains(banned)) {
    System.out.println("不適切な言葉が含まれています。");
}

Gestion de plusieurs mots NG :

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

5-2. Analyse de fichiers journaux (détection de messages spécifiques)

Lors de l’analyse des journaux système ou d’application, vous pouvez vouloir extraire uniquement les lignes contenant des mots‑clés spécifiques comme ERROR ou WARN.

List<String> logs = Arrays.asList(
    "[INFO] サーバーが起動しました",
    "[ERROR] データベース接続失敗",
    "[WARN] メモリ使用率が高い"
);

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

5-3. Filtrage de chaînes dans une liste (en utilisant l’API Stream)

Lors du traitement de grands ensembles de données, utilisez l’API Stream pour extraire uniquement les éléments contenant une sous‑chaîne spécifique :

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. Analyse des en‑têtes de requête HTTP ou des URL

En développement web, le routage ou la gestion spécifique à un appareil peut nécessiter la vérification de sous‑chaînes dans le User‑Agent ou l’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. Vérification des chemins de fichiers ou des extensions

Pour déterminer le type d’un fichier à partir de son chemin :

String filePath = "/usr/local/data/sample.csv";
if (filePath.contains(".csv")) {
    System.out.println("CSVファイルです。");
}

Remarque :
Pour la vérification des extensions de fichiers, endsWith(".csv") est souvent plus précis.

Considérations pratiques

  • Appliquez la normalisation (par ex., toLowerCase(), trim()) lorsque la précision est requise.
  • Pour les données à grande échelle, envisagez l’API Stream ou les expressions régulières.
  • Rappelez‑vous que contains() effectue une correspondance partielle — combinez‑le avec d’autres conditions pour une logique plus sûre.

6. Considérations de performance

Bien que la méthode contains() offre une excellente lisibilité et simplicité, vous devez prendre en compte son impact sur les performances lors du traitement de grands ensembles de données ou d’opérations répétées.
Cette section explique le coût de traitement de contains() et les approches alternatives pour améliorer l’efficacité.

6-1. Comportement interne et complexité temporelle de contains()

La méthode contains() recherche la chaîne cible séquentiellement depuis le début pour localiser la sous‑chaîne.
En interne, elle s’appuie sur la méthode indexOf(), et sa complexité temporelle dans le pire des cas est :

O(n * m)
– n = longueur de la chaîne cible
– m = longueur de la chaîne recherchée

Exemple de traitement intensif :

for (String line : hugeTextList) {
    if (line.contains("error")) {
        // processing
    }
}

Cela peut affecter considérablement les performances lorsqu’il est répété dans de grandes boucles.

6-2. Techniques pour améliorer les performances lors de recherches fréquentes

Lors de l’utilisation répétée de contains() sur de grands ensembles de données, les techniques suivantes peuvent améliorer la vitesse de traitement :

• Convertir toutes les chaînes en minuscules à l’avance

Au lieu d’appeler toLowerCase() à chaque comparaison, normalisez les chaînes à l’avance :

List<String> normalizedList = originalList.stream()
    .map(String::toLowerCase)
    .collect(Collectors.toList());
• Utiliser l’API Stream avec parallel() pour le traitement parallèle

Utilisez les cœurs du CPU pour accélérer les recherches :

List<String> result = hugeTextList.parallelStream()
    .filter(line -> line.contains("keyword"))
    .collect(Collectors.toList());
• Utiliser les expressions régulières pour des modèles de recherche complexes

Si les conditions sont complexes et peuvent être exprimées en une seule expression régulière, Pattern peut être plus performant :

Pattern pattern = Pattern.compile("error|fail|fatal");
for (String log : logs) {
    if (pattern.matcher(log).find()) {
        // matched
    }
}

6-3. Considérations d’efficacité mémoire et de réutilisabilité

Les opérations qui convertissent fréquemment des chaînes—comme toLowerCase() ou substring()—peuvent générer de nombreux objets de chaîne inutiles, affectant l’utilisation de la mémoire. Cela est particulièrement important pour les applications à long terme ou le traitement côté serveur.

Points clés :

  • Éviter de créer des instances de chaîne inutiles.
  • Pour de grands ensembles de données, envisager le tamponnage ou le traitement par blocs.
  • Mettre en cache les résultats répétés de contains() peut améliorer les performances dans certains cas.

7. Comparaison avec d’autres langages de programmation

La méthode contains() de Java offre une correspondance de sous‑chaîne simple et fiable, mais d’autres langages proposent des fonctionnalités similaires avec leurs propres caractéristiques. Cette section compare la vérification de sous‑chaîne en Python, JavaScript et C# afin de mettre en évidence les différences et similitudes.

7-1. Python : correspondance partielle simple avec l’opérateur in

En Python, vous pouvez vérifier l’inclusion d’une sous‑chaîne à l’aide de l’opérateur in :

text = "Hello, Python!"
if "Python" in text:
    print("含まれています")

Cette syntaxe est extrêmement lisible—presque comme du langage naturel—et nécessite peu d’apprentissage.

Différences et notes  :

  • in est un opérateur du langage, pas une méthode.
  • Python est également sensible à la casse pour la comparaison de chaînes.
  • None génère une exception ; des vérifications de nullité sont nécessaires.

7-2. JavaScript : correspondance partielle avec includes()

En JavaScript (ES6+), vous pouvez utiliser la méthode includes() :

const text = "JavaScript is fun";
console.log(text.includes("fun")); // true

Cette méthode est très similaire à contains() de Java et facile à adopter mentalement.

Différences et notes  :

  • Passer undefined ne génère pas d’exception ; cela renvoie simplement false.
  • includes() fonctionne également sur les tableaux, augmentant ainsi sa polyvalence.

7-3. C# : Contains() similaire à Java

C# propose également une méthode Contains() avec un comportement similaire à Java :

string text = "Welcome to C#";
bool result = text.Contains("C#");

Différences et notes  :

  • Contains() en C# est sensible à la casse par défaut, mais vous pouvez ignorer la casse en utilisant StringComparison.OrdinalIgnoreCase.
  • Passer null déclenche une ArgumentNullException.

7-4. Tableau comparatif entre les langages

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

Résumé : choisissez la syntaxe adaptée à votre cas d’utilisation

Bien que la vérification de sous‑chaîne soit une exigence courante dans tous les langages, chaque langage propose sa propre méthode ou syntaxe. Le contains() de Java offre stabilité et clarté, ce qui le rend bien adapté aux systèmes d’entreprise et aux applications maintenables. Des langages comme Python et JavaScript offrent une syntaxe plus simple et concise, idéale pour les scripts légers ou le prototypage rapide.

En comprenant à la fois les concepts communs et les fonctionnalités spécifiques de chaque langage, vous pourrez écrire du code plus sûr et plus efficace dans divers langages.

8. Questions fréquemment posées (FAQ)

Voici les questions les plus fréquemment posées concernant la méthode contains() de Java—vous aidant à comprendre les points délicats et à éviter les pièges courants.

Q1. contains() est-il sensible à la casse ?

Oui, il est sensible à la casse. Par exemple, "Java".contains("java") renvoie false.

Solution  :

String input = "Welcome to Java";
boolean result = input.toLowerCase().contains("java");

Q2. Comment vérifier des correspondances partielles à l’aide d’expressions régulières ?

contains() ne prend pas en charge les expressions régulières.
Utilisez matches() ou la classe Pattern à la place.

Exemple (vérification d’un motif numérique) :

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. Que se passe-t-il si j’appelle contains() sur null ?

Une NullPointerException sera levée.

String target = null;
System.out.println(target.contains("test")); // Error

Solution :

if (target != null && target.contains("test")) {
    System.out.println("含まれています。");
}

Q4. Que se passe-t-il si je passe une chaîne vide («  ») à contains() ?

Elle renvoie toujours true.

String text = "Java";
System.out.println(text.contains("")); // true

Bien que cela fasse partie de la spécification officielle, ce comportement est rarement utile et peut entraîner des bugs inattendus si les chaînes vides ne sont pas prévues.

Q5. contains() peut-il rechercher plusieurs mots‑clés à la fois ?

Non. Chaque appel ne vérifie qu’un seul mot‑clé.

String text = "本日はシステムエラーが発生しました";
if (text.contains("エラー") || text.contains("障害") || text.contains("失敗")) {
    System.out.println("問題が検出されました。");
}

Approche dynamique :

List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(text::contains);

Q6. Quand faut‑il utiliser contains() plutôt que indexOf() ?

contains() renvoie un booléen, tandis que indexOf() renvoie un indice numérique.

  • Utilisez contains() lorsque vous voulez simplement savoir si la sous‑chaîne existe.
  • Utilisez indexOf() lorsque vous avez également besoin de la position.
    String text = "Error: Disk full";
    if (text.contains("Error")) {
        int pos = text.indexOf("Error");
        System.out.println("Position: " + pos);
    }
    

9. Conclusion

La méthode contains() de Java est un outil puissant et pratique pour déterminer si une sous‑chaîne spécifique est contenue dans une chaîne.
Elle est largement utilisée dans divers scénarios tels que la validation d’entrées utilisateur, l’analyse de journaux et le filtrage de données.

Dans cet article, nous avons couvert :

  • Syntaxe de base et valeurs de retour
  • Sensibilité à la casse et comment la gérer
  • Gestion des nulls et des chaînes vides
  • Différences avec d’autres méthodes de comparaison de chaînes
  • Cas d’utilisation pratiques : validation, recherche dans les journaux, traitement de flux
  • Considérations de performance et techniques d’optimisation
  • Comparaison avec Python, JavaScript et C#
  • FAQ et conseils de dépannage

Bien que contains() soit intuitif et polyvalent, son utilisation doit être évaluée avec soin dans les cas impliquant des grands ensembles de données, des appels fréquents ou des conditions de recherche complexes.
En combinant normalisation, traitement parallèle, expressions régulières et stratégies de mise en cache, vous pouvez conserver à la fois performance et lisibilité.

Étant donné que contains() est fondamental pour travailler avec les chaînes en Java, nous espérons que cet article vous aidera à l’utiliser de manière plus sûre et efficace dans vos projets de développement.