Maîtriser la comparaison de chaînes en Java : différences entre “==”, equals(), compareTo() et meilleures pratiques

目次

1. Introduction

Pourquoi la comparaison de chaînes est‑elle importante en Java ?

En programmation Java, les chaînes sont utilisées dans de nombreuses situations. Vérifier les noms d’utilisateur, valider les entrées de formulaire et vérifier les réponses d’API nécessitent tous de comparer des chaînes.
À ce stade, « comment comparer correctement les chaînes » constitue un obstacle fréquent pour les débutants. En particulier, ne pas comprendre la différence entre l’opérateur == et la méthode equals() peut entraîner des bugs inattendus.

Le danger de ne pas comprendre la différence entre “==” et “equals”

Considérez le code suivant :

String a = "apple";
String b = new String("apple");

System.out.println(a == b);       // result: false
System.out.println(a.equals(b));  // result: true

Beaucoup de gens sont surpris par ce résultat. Même si les chaînes sont identiques, == renvoie false alors que equals() renvoie true. Cela se produit parce que Java traite les chaînes comme des types de référence, et == compare les adresses de référence.
Comprendre la bonne façon de comparer les chaînes influence directement la fiabilité et la lisibilité de votre programme. Si vous la maîtrisez correctement, vous pouvez prévenir les bugs avant qu’ils ne surviennent.

Ce que vous apprendrez dans cet article

Cet article explique la comparaison de chaînes en Java, des bases aux applications pratiques. Il répond à des questions telles que :

  • Quelle est la différence entre == et equals() ?
  • Comment comparer des chaînes en ignorant la casse ?
  • Comment comparer des chaînes lexicographiquement ?
  • Comment éviter les exceptions lors de la comparaison avec null ?

À travers des exemples concrets, vous acquerrez une compréhension solide des bonnes pratiques de comparaison de chaînes.

2. Bases des chaînes en Java

Les chaînes sont des types de référence

En Java, le type String n’est pas un type primitif (comme int ou boolean) mais un type de référence. Une variable String ne stocke pas les caractères réels mais une référence à un objet stocké dans la mémoire du tas.
Par exemple :

String a = "hello";
String b = "hello";

a et b peuvent tous deux référencer le même littéral "hello" grâce au mécanisme d’internement des chaînes de Java.

Différence entre les littéraux de chaîne et new String()

Java optimise les littéraux de chaîne répétés en réutilisant la même référence :

String s1 = "apple";
String s2 = "apple";
System.out.println(s1 == s2); // true (same literal, interned)

Cependant, l’utilisation de new crée toujours un nouvel objet :

String s3 = new String("apple");
System.out.println(s1 == s3); // false (different references)
System.out.println(s1.equals(s3)); // true (same content)

Ainsi, == vérifie la référence et equals() vérifie le contenu.

Les chaînes sont immuables

Une autre caractéristique clé est que String est immuable. Une fois créée, une chaîne ne peut pas être modifiée.

String original = "hello";
original = original + " world";

Cela crée un nouvel objet String plutôt que de modifier l’original.

3. Méthodes de comparaison des chaînes

Comparaison des références avec ==

== compare les références d’objets :

String a = "Java";
String b = new String("Java");

System.out.println(a == b); // false

Il ne doit pas être utilisé pour la comparaison de contenu.

Comparaison du contenu avec equals()

equals() est la façon correcte de comparer le contenu des chaînes :

String a = "Java";
String b = new String("Java");

System.out.println(a.equals(b)); // true

Éviter le NullPointerException

String input = null;
System.out.println(input.equals("test")); // Exception!

Utilisez le style constant‑first :

System.out.println("test".equals(input)); // false, safe

Ignorer la casse avec equalsIgnoreCase()

String a = "Hello";
String b = "hello";

System.out.println(a.equalsIgnoreCase(b)); // true

Comparaison lexicographique avec compareTo()

  • 0 → égal
  • Négatif → l’appelant précède
  • Positif → l’appelant suit
    String a = "apple";
    String b = "banana";
    
    System.out.println(a.compareTo(b)); // negative
    

4. Exemples pratiques

Vérification de connexion utilisateur

String inputUsername = "Naohiro";
String registeredUsername = "naohiro";

if (registeredUsername.equalsIgnoreCase(inputUsername)) {
    System.out.println("Login successful");
} else {
    System.out.println("Username does not match");
}

Les mots de passe doivent toujours utiliser equals() car la sensibilité à la casse est requise.

Validation des entrées de formulaire

String selectedOption = request.getParameter("plan");

if ("premium".equals(selectedOption)) {
    System.out.println("Premium plan selected.");
} else {
    System.out.println("Other plan selected.");
}

Logique de branchement avec plusieurs vérifications de chaînes

String cmd = args[0];

if ("start".equals(cmd)) {
    startApp();
} else if ("stop".equals(cmd)) {
    stopApp();
} else {
    System.out.println("Invalid command");
}
switch (cmd) {
    case "start":
        startApp();
        break;
    case "stop":
        stopApp();
        break;
    default:
        System.out.println("Unknown command");
}

Gestion sécurisée du null

String keyword = null;

if ("search".equals(keyword)) {
    System.out.println("Searching...");
}

5. Performance et optimisation

Coût des comparaisons de chaînes

equals() et compareTo() comparent les caractères en interne. Pour de longues chaînes ou des comparaisons répétées, cela peut affecter les performances.

Utilisation de String.intern() pour la performance

String a = new String("hello").intern();
String b = "hello";

System.out.println(a == b); // true

Utilisez uniquement si nécessaire pour éviter la pression mémoire.

Impact sur la performance de equalsIgnoreCase()

String input = userInput.toLowerCase();
if ("admin".equals(input)) {
    // fast comparison
}

Utilisation de StringBuilder / StringBuffer

StringBuilder sb = new StringBuilder();
sb.append("user_");
sb.append("123");

String result = sb.toString();

if (result.equals("user_123")) {
    // comparison
}

Utilisation du cache ou de maps pour réduire les comparaisons

Map<String, Runnable> commandMap = new HashMap<>();
commandMap.put("start", () -> startApp());
commandMap.put("stop", () -> stopApp());

Runnable action = commandMap.get(inputCommand);
if (action != null) {
    action.run();
}

6. FAQ

Q1. Quelle est la différence entre == et equals() ?

R.

  • == compare les références
  • equals() compare le contenu de la chaîne

Q2. Pourquoi equals() génère-t-il une erreur lorsque la variable est null ?

String input = null;
input.equals("test"); // Exception

Utilisez une comparaison où la constante est en premier :

"test".equals(input);

Q3. Comment comparer des chaînes en ignorant la casse ?

stringA.equalsIgnoreCase(stringB);

Q4. Comment comparer l’ordre alphabétique ?

a.compareTo(b);

7. Conclusion

Choisir correctement la bonne méthode de comparaison est important

Parce que String est un type de référence, une comparaison incorrecte conduit souvent à un comportement inattendu. Comprendre == vs equals() est essentiel.

Checklist

  • == : compare les références
  • equals() : compare le contenu
  • equalsIgnoreCase() : ignore la casse
  • compareTo() : ordre lexical
  • "constant".equals(variable) : sûr pour le null
  • Utilisez intern() ou le cache pour les comparaisons intensives

Connaissances pratiques et essentielles

La comparaison de chaînes apparaît dans les vérifications de connexion, la validation, les opérations de base de données, la logique de branchement et de nombreuses tâches quotidiennes. Connaître les bonnes techniques aide à écrire un code plus sûr et plus fiable. Utilisez ce guide comme référence lors de la manipulation de chaînes en Java.