Java · Fiche 06

Strings & Immutabilité

Immutabilité des String en Java, String Pool, StringBuilder vs StringBuffer et méthodes essentielles de manipulation de chaînes.

Gestion des chaînes de caractères et concept d’immutabilité en Java.

🔒 Immutabilité des Strings

Qu’est-ce que l’immutabilité ?

Une fois créée, une String ne peut pas être modifiée. Toute « modification » crée une nouvelle String.

String str = "Hello";
System.out.println(str.hashCode()); // Ex: 69609650

str = str + " World";
System.out.println(str.hashCode()); // Ex: 1794106052 (différent !)

// La String originale "Hello" existe toujours en mémoire
// Une nouvelle String "Hello World" a été créée

Pourquoi l’immutabilité ?

  • Sécurité : pas de modification accidentelle
  • Thread-safety : partage sûr entre threads
  • Hashcode stable : utilisation dans HashMap
  • String Pool : optimisation mémoire
  • Sécurité : mots de passe, URLs, etc.

Attention : concaténer des Strings en boucle crée beaucoup d’objets temporaires !

🏊 String Pool (Intern Pool)

Mécanisme du String Pool

// Littéraux String vont dans le pool
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true (même référence)

// new String() crée un nouvel objet
String s3 = new String("Hello");
System.out.println(s1 == s3); // false (références différentes)
System.out.println(s1.equals(s3)); // true (même contenu)

// intern() force l'ajout au pool
String s4 = s3.intern();
System.out.println(s1 == s4); // true (même référence du pool)

Optimisation mémoire

Avantages du Pool :

  • Économie de mémoire
  • Comparaison rapide avec ==
  • Réutilisation automatique

Attention :

  • Pool en mémoire permanente
  • intern() peut causer des fuites
  • Utiliser avec parcimonie

🔧 StringBuilder vs StringBuffer

Alternatives mutables pour la manipulation de chaînes.

StringBuilder (recommandé)

// StringBuilder - Non thread-safe mais plus rapide
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
sb.insert(5, " Beautiful");
sb.delete(5, 15); // Supprime " Beautiful"

String result = sb.toString(); // "Hello World"

// Exemple avec boucle
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    builder.append("Item ").append(i).append(", ");
}
String list = builder.toString();

StringBuffer (legacy)

// StringBuffer - Thread-safe mais plus lent
StringBuffer buffer = new StringBuffer();
buffer.append("Thread-safe");
buffer.append(" concatenation");

// Méthodes synchronisées
public synchronized StringBuffer append(String str) {
    // Implémentation thread-safe
}

// Utilisation en environnement multi-thread
public class ThreadSafeStringBuilder {
    private StringBuffer buffer = new StringBuffer();

    public void addMessage(String msg) {
        buffer.append(msg).append("\n");
    }

    public String getMessages() {
        return buffer.toString();
    }
}

Comparaison des performances

Opération String StringBuilder StringBuffer
Concaténation simple ❌ Lent (O(n²)) ✅ Rapide (O(n)) ⚠️ Moyen (O(n))
Thread-safety ✅ Immutable ❌ Non thread-safe ✅ Thread-safe
Mémoire ❌ Beaucoup d’objets ✅ Buffer réutilisé ✅ Buffer réutilisé

🛠️ Méthodes String essentielles

Manipulation de base

String text = "  Hello World  ";

// Longueur et vérifications
text.length();                    // 15
text.isEmpty();                   // false
text.isBlank();                   // false (Java 11+)

// Nettoyage
text.trim();                      // "Hello World"
text.strip();                     // "Hello World" (Java 11+, Unicode)
text.stripLeading();              // "Hello World  "
text.stripTrailing();             // "  Hello World"

// Casse
text.toUpperCase();               // "  HELLO WORLD  "
text.toLowerCase();               // "  hello world  "

// Recherche
text.contains("World");           // true
text.startsWith("  Hello");       // true
text.endsWith("World  ");         // true
text.indexOf("World");            // 8
text.lastIndexOf("l");            // 11

Extraction et division

String data = "Java,Python,JavaScript";

// Extraction
data.substring(5);                // "Python,JavaScript"
data.substring(5, 11);            // "Python"
data.charAt(0);                   // 'J'

// Division
String[] languages = data.split(",");
// ["Java", "Python", "JavaScript"]

// Remplacement
data.replace(",", " | ");         // "Java | Python | JavaScript"
data.replaceAll("\\w+", "Lang");  // "Lang,Lang,Lang" (regex)
data.replaceFirst("Java", "Kotlin"); // "Kotlin,Python,JavaScript"

// Répétition (Java 11+)
"Ha".repeat(3);                   // "HaHaHa"

// Jointure (Java 8+)
String joined = String.join(", ", languages);
// "Java, Python, JavaScript"

✅ Bonnes pratiques

À faire

Utiliser StringBuilder pour les concaténations multiples :

StringBuilder sb = new StringBuilder();
for (String item : items) {
    sb.append(item).append(", ");
}
return sb.toString();

Utiliser equals() pour comparer le contenu :

if ("expected".equals(userInput)) {
    // Évite NullPointerException
}

À éviter

Concaténation en boucle avec + :

String result = "";
for (String item : items) {
    result += item + ", "; // Crée beaucoup d'objets !
}

Comparaison avec == :

if (str1 == str2) {
    // Dangereux ! Compare les références
}

Piège d’entretien : == compare les références, pas le contenu. Deux littéraux identiques peuvent renvoyer true à cause du String Pool, mais un new String("...") renverra false — utilisez toujours equals().

Interro écrite

7 questions pour valider la fiche. Une seule réponse par question.

Question 1/7Que signifie l'immutabilité d'une String en Java ?