03.08 StringBuffer und StringBuilder

Wie Sie wissen, sind Strings immutable und somit unveränderbar. Dies hat zur Folge, dass bei jeder Verknüpfung von Strings mit dem + Operator ein neuer String erzeugt wird, was in den meisten Fällen nicht gerade performant ist. Zwei Alternativen lernen Sie in diesem Kapitel kennen.

Ein Nachteil von Strings

Betrachten wir das oben angesprochene Problem noch einmal in der Praxis. Wenn Sie viele Zeichen einer Zeichenkette in einer Schleife hinzufügen, wird die Geschwindigkeit der Anwendung sehr schnell einbrechen. Führen Sie hierzu folgende Beispielanwendung aus:

package de.jbb;

public class Test {

  public static void main(String[] args) {
o
    String str = "";
    for (int i = 0; i < 100000; i++) {
      str += i;
    }
  }
}

Sie werden feststellen, dass das Programm ungewöhnlich lange läuft. Dies liegt wie bereits erwähnt daran, dass bei jedem Schleifendurchlauf ein neuer String erzeugt wird.

Die Lösung

Verwenden Sie allerdings anstelle eines Strings einen StringBuilder oder einen StringBuffer, verschwindet das Geschwindigkeits-Problem.

package de.jbb;

public class Test {

  public static void main(String[] args) {
o
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < 100000; i++) {
      str.append(i);
    }
  }
}

Einsatzorte von String, StringBuilder und StringBuffer

Aber sollten Sie deshalb immer einen StringBuilder oder StringBuffer anstelle eines Strings verwenden? Nein! Denn Strings werden vom Compiler automatisch in StringBuffer bzw. StringBuilder umgewandelt. Dies funktioniert aber nicht immer, wie Sie beim ersten Beispiel in diesem Kapitel festgestellt haben. Aus

String str = "Simpler";
str += " String";
String str2 = "";
for (int i = 0; i < 10; i++) {
  str2 += str2.length();
}

macht der Compiler automatisch bspw. das hier:

String s = "Simpler";
s = (new StringBuilder()).append(s).append(" String").toString();
String s1 = "";
for(int i = 0; i < 10; i++)
  s1 = (new StringBuilder()).append(s1).append(s1.length()).toString();

Sie sehen, dass der Compiler die Verbindung von Strings, die außerhalb einer Schleife, also nicht dynamisch zusammengebaut werden, soweit akzeptabel löst. In der Schleife wird allerdings grober Unfug erzeugt, der garantiert nicht für die Performance förderlich ist.

Deshalb sollten Sie immer dann auf diese beiden Alternativen ausweichen, wenn es wichtig ist, dass Ihre Zeichenkette dynamisch veränderbar (z. B. in einer Schleife) ist, oder wenn Sie auf deren zusätzlichen Methoden wie z. B. insert (zusätzlichen Inhalt an eine beliebigen Stelle einfügen), setCharAt (ein Zeichen an einer bestimmten Stelle ersetzen), oder reverse (umkehren der Zeichenkette) zugreifen müssen/möchten. Die genauen Methodenaufrufe finden Sie in der Dokumentation zum StringBuilder bzw. StringBuffer. Bei der Entscheidung, ob Sie einen StringBuilder oder einen StringBuffer verwenden, sollten Sie beachten, dass ein StringBuffer im Gegensatz zum StringBuilder synchronisiert ist (mehr dazu lernen Sie im Kapitel über Threads), und dass es den StringBuilder erst seit Java 5 gibt (StringBuffer seit Java 1.0).

StringBuilder und StringBuffer in Kombination mit String

StringBuilder, StringBuffer und String sind nicht miteinander verwandt. Dadurch ist ein Vergleich, wie Sie ihn aus Kapitel 03.02 Strings vergleichen kennen, nicht mehr möglich. Wenn Sie StringBuilder und StringBuffer miteinander oder mit einem gewöhnlichen String vergleichen wollen, müssen Sie diese vorher in einen String mit der toString-Methode umwandeln.

StringBuilder build = new StringBuilder("123");
String str = "123";
StringBuffer buff = new StringBuffer("123");
System.out.println(build.equals(buff)); // false
System.out.println(buff.equals(str)); // false
System.out.println(buff.toString().equals(build.toString())); // true
System.out.println(str.equals(buff.toString())); // true

Dies gilt übrigens auch für scheinbar gleiche Instanzen selben Typs:

StringBuffer buffer = new StringBuffer("123");
StringBuffer buffer2 = new StringBuffer("123");
System.out.println(buffer.equals(buffer2)); // false

StringBuilder builder = new StringBuilder("123");
StringBuilder builder2 = new StringBuilder("123");
System.out.println(builder.equals(builder2)); // false

Über die String-Methode contentEquals können Sie aber zumindest den Inhalt eines Strings direkt mit dem eines StringBuilders oder StringBuffers vergleichen. Wenn Sie einen StringBuffer mit einem StringBuilder vergleichen möchten, müssen Sie trotzdem noch mindestens einen von beiden in einen gewöhnlichen String umwandeln.

StringBuilder build = new StringBuilder("123");
String str = "123";
StringBuffer buff = new StringBuffer("123");
System.out.println(str.contentEquals(buff)); // true
System.out.println(build.toString().contentEquals(buff)); // true

Ähnliche Beiträge