1. Unveränderlichkeit von Strings: Freund oder Feind?
In Java ist die Klasse String unveränderlich (immutable). Das bedeutet, dass man einen String nach seiner Erstellung nicht ändern kann. Jedes Mal, wenn Sie den String „ändern“, zum Beispiel etwas mit + oder concat() anhängen, wird in Wirklichkeit ein neues Objekt erzeugt und das alte wandert auf den Müllhaufen der Geschichte (und des Speichers).
Beispiel:
String s = "Hello";
s = s + " world!";
System.out.println(s); // Hello world!
Es sieht so aus, als hätte sich der String s geändert, tatsächlich wurde aber der neue String "Hello world!" erstellt, während der alte "Hello" im Speicher bleibt, bis der Garbage Collector ihn entfernt. Wenn es viele solcher Operationen gibt – etwa in einer Schleife –, wird das Programm langsamer und verbraucht unnötig Speicher.
Stellen Sie sich vor, Sie bauen einen Turm aus Bauklötzen und müssten bei jedem neuen Stein den ganzen Turm neu aufbauen. Nicht sehr effizient, oder? Genau so verhält sich ein gewöhnlicher String in Java bei häufigen Änderungen.
2. StringBuilder: der schnelle „String-Baukasten“
Die Klasse StringBuilder (Paket java.lang, kein Import nötig) ist ein spezielles Werkzeug zum effizienten Zusammenbauen und Ändern von Strings. Er ist veränderlich (mutable): Sie können Zeichen und Teilstrings hinzufügen, löschen und einfügen, ohne für jede Operation ein neues Objekt zu erzeugen.
Analogie:
Wenn String eine Betonplatte ist, dann ist StringBuilder ein LEGO-Baukasten: Sie fügen Teile hinzu oder entfernen sie, so oft Sie wollen, ohne alles neu aufbauen zu müssen.
StringBuilder erstellen
StringBuilder sb = new StringBuilder(); // leer
StringBuilder sb2 = new StringBuilder("Anfangswert");
Wichtige Methoden
| Methode | Beschreibung | Beispiel |
|---|---|---|
|
Am Ende einen String, eine Zahl, ein Zeichen usw. anhängen | |
|
Wert an der angegebenen Position einfügen | |
|
Zeichen von Position start (inkl.) bis end (exkl.) löschen | |
|
Teil des Strings durch anderen Inhalt ersetzen | |
|
String umkehren | |
|
In normalen String umwandeln | |
|
String auf die angegebene Länge kürzen oder auffüllen | |
Beispiel
StringBuilder sb = new StringBuilder();
sb.append("Hallo, ");
sb.append("Welt!");
System.out.println(sb); // Hallo, Welt!
sb.insert(7, "Java "); // "Java " nach "Hallo, " einfügen
System.out.println(sb); // Hallo, Java Welt!
sb.replace(8, 12, "anderes"); // "Java" durch "anderes" ersetzen
System.out.println(sb); // Hallo, anderes Welt!
sb.reverse();
System.out.println(sb); // !tleW seredna ,ollaH
3. StringBuffer: der große Bruder mit Thread-Sicherheit
Worin besteht der Unterschied zwischen StringBuilder und StringBuffer?
- StringBuilder – schnell, aber nicht threadsicher (nicht synchronisiert).
- StringBuffer – langsamer, dafür threadsicher (synchronisiert).
Wenn Ihre Anwendung nur in einem Thread läuft – verwenden Sie StringBuilder (schneller). Wenn mehrere Threads denselben String ändern können – verwenden Sie StringBuffer.
4. Wann sollte man StringBuilder statt String verwenden?
Szenarien
- Häufige Änderungen am String (Anhängen, Löschen, Einfügen) in einer Schleife oder beim Zusammenbauen großer Texte.
- Zusammenbau eines Strings aus Array/Liste (CSV, HTML, Berichte usw.).
- Parsing und Textverarbeitung mit vielen Operationen auf Strings.
Beispiel: String aus einem Array zusammenbauen
Schlechter Ansatz (mit String und +):
String[] names = {"Ivan", "Pyotr", "Mariya"};
String result = "";
for (int i = 0; i < names.length; i++)
{
result += names[i];
if (i < names.length - 1)
{
result += ", ";
}
}
System.out.println(result);
Guter Ansatz (mit StringBuilder):
String[] names = {"Ivan", "Pyotr", "Mariya"};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < names.length; i++)
{
sb.append(names[i]);
if (i < names.length - 1)
{
sb.append(", ");
}
}
System.out.println(sb.toString());
Unterschied: Im ersten Fall wird bei jedem Schritt ein neuer String erzeugt, im zweiten bauen wir ein einziges StringBuilder-Objekt auf.
5. Leistungsvergleich: String vs StringBuilder
// Mit String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " ms");
// Mit StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " ms");
Fazit: In den meisten Fällen ist StringBuilder bei vielen Konkatenationen um Größenordnungen schneller.
6. Nützliche Feinheiten
Kann man String-Methoden verwenden?
StringBuilder hat eigene Methoden. Um einen String zu erhalten, rufen Sie toString() auf.
StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString(); // jetzt ist s ein normaler String
Kann man StringBuilder mit equals vergleichen?
Vorsicht: sb1.equals(sb2) vergleicht Referenzen, nicht den Inhalt. Vergleichen Sie so:
if (sb1.toString().equals(sb2.toString()))
{
// der Inhalt ist gleich
}
Kann man StringBuilder an System.out.println übergeben?
Ja. System.out.println ruft toString() automatisch auf.
Kann man Zeichen per Index lesen?
Ja, verwenden Sie charAt(int index), wie bei einem gewöhnlichen String.
7. Typische Fehler bei der Arbeit mit StringBuilder und StringBuffer
Fehler Nr. 1: zwei StringBuilder mit equals oder dem Operator == vergleichen. Diese Prüfungen vergleichen Referenzen, nicht den Inhalt. Verwenden Sie toString() und den Vergleich der Strings.
Fehler Nr. 2: toString() dort zu vergessen, wo ein String erwartet wird (Rückgabewert, Logging, Übergabe an ein API).
Fehler Nr. 3: String für ein paar einfache Konkatenationen durch + ersetzen. Die Schreibweise "Hello, " + name ist gut lesbar und effizient.
Fehler Nr. 4: String in einer Schleife mit + zu konkatinieren. Das ist zeit- und speicherineffizient – verwenden Sie StringBuilder.
Fehler Nr. 5: StringBuffer und StringBuilder ohne Not zu verwechseln. Wenn keine gemeinsame Modifikation aus mehreren Threads stattfindet, wählen Sie StringBuilder.
Fehler Nr. 6: den Inhalt von StringBuilder gedankenlos mit setLength() zu kürzen. Prüfen Sie die neue Länge sorgfältig; Daten hinter dieser Position gehen verloren.
GO TO FULL VERSION