Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5 (Tiger-Release)
Buch: Java ist auch eine Insel
gp Kapitel 4 Der Umgang mit Zeichenketten
  gp 4.1 Strings und deren Anwendung
    gp 4.1.1 String-Objekte für konstante Zeichenketten
    gp 4.1.2 String-Länge
    gp 4.1.3 Gut, dass wir verglichen haben
    gp 4.1.4 String-Teile extrahieren
    gp 4.1.5 Suchen und Ersetzen
    gp 4.1.6 Veränderte Strings liefern
    gp 4.1.7 Unterschiedliche Typen in Zeichenketten konvertieren
  gp 4.2 Veränderbare Zeichenketten mit StringBuffer/StringBuilder
    gp 4.2.1 Anlegen von StringBuffer-Objekten
    gp 4.2.2 Die Länge eines StringBuffer-Objekts lesen und setzen
    gp 4.2.3 Daten anhängen
    gp 4.2.4 Zeichen(folgen) setzen, erfragen, löschen und umdrehen
  gp 4.3 Vergleiche von Zeichenketten
    gp 4.3.1 equals() in String und StringBuffer
    gp 4.3.2 Sollte es ein equals() und hash() bei StringBuffer geben?
    gp 4.3.3 Sprachabhängiges Vergleichen mit der Collator-Klasse
    gp 4.3.4 Effiziente interne Speicherung für die Sortierung
  gp 4.4 Zeichenkodierungen
    gp 4.4.1 Standard-Encodings
    gp 4.4.2 Base64-Kodierung
  gp 4.5 Reguläre Ausdrücke
  gp 4.6 Zerlegen von Zeichenketten
    gp 4.6.1 StringTokenizer
    gp 4.6.2 Splitten von Zeichenketten mit split() aus Pattern
    gp 4.6.3 split() in String
    gp 4.6.4 Die neue Klasse Scanner
    gp 4.6.5 Der BreakIterator als Wort- und Satztrenner
  gp 4.7 Formatieren von Ausgaben
    gp 4.7.1 Prozente, Zahlen und Währungen ausgeben mit NumberFormat
    gp 4.7.2 Ausgaben formatieren mit MessageFormat
    gp 4.7.3 Dezimalzahlformatierung mit DecimalFormat
    gp 4.7.4 Formatieren mit format()


Galileo Computing

4.2 Veränderbare Zeichenketten mit StringBuffer/StringBuilder  downtop

Zeichenketten, die in der virtuellen Maschine in String-Objekten gespeichert sind, haben die Eigenschaft, dass ihr Inhalt nicht mehr verändert werden kann. Anders verhalten sich die Exemplare der Klasse StringBuffer und StringBuilder an denen sich Veränderungen vornehmen lassen. Die Veränderungen betreffen anschließend das StringBuffer/StringBuilder -Objekt selbst, und es wird kein neu erzeugtes Objekt als Ergebnis geliefert, wie zum Beispiel beim Plus-Operator und der concat()-Methode bei herkömmlichen String-Objekten. Sonst sind sich aber die Implementierung von String-Objekten und StringBuffer/StringBuffer-Objekten ähnlich. In beiden Fällen nutzen die Klassen ein internes Zeichenfeld. Bei String-Objekten kann jedoch durch eine Optimierung die Methode substring() ohne Kopie der Teilzeichenkette auskommen, und das interne Feld lässt sich mehrfach verwenden. StringBuffer/StringBuilder muss das eigene Array immer wieder kopieren.

Durch die Symmetrie der Klasse StringBuffer/StringBuilder wird im Folgenden nur noch StringBuffer vorgestellt. Die Klasse StringBuilder bietet die gleichen Funktionen wie StringBuffer, nur nicht synchronisiert. Bei nebenläufigen Programmen kann daher die interne Datenstruktur vom StringBuilder inkonsistent werden, ist aber dafür bei nicht-nebenläufigen Zugriffen ein wenig schneller.


Galileo Computing

4.2.1 Anlegen von StringBuffer-Objekten  downtop

Mit drei Konstruktoren lassen sich StringBuffer-Objekte generieren.



final class java.lang.  StringBuffer  
implements CharSequence, Serializable

gp  StringBuffer()
Legt ein StringBuffer-Objekt an, das die leere Zeichenreihe enthält und Platz für (zunächst) bis zu 16 Zeichen bietet. Bei Bedarf wird automatisch Platz für weitere Zeichen bereitgestellt.
gp  StringBuffer( int length )
Wie oben, jedoch reicht die anfängliche Kapazität des StringBuffer-Objekts für die angegebene Anzahl Zeichen.
gp  StringBuffer( String str )
Ein StringBuffer, welches eine Kopie der Zeichen aus str enthält. Zusätzlich wird bereits Platz für 16 weitere Zeichen eingeplant.
gp  StringBuffer( CharSequence seq )
Erzeugt einen neuen StringBuffer aus einer CharSequence. Damit können auch andere StringBuffer und StringBuilder-Objekte einen neuen StringBuffer erzeugen.

Da nur String-Objekte von der Sprache bevorzugt werden, bleibt uns allein der explizite Aufruf eines Konstruktors, um StringBuffer-Exemplare anzulegen. Alle String-Literale in Anführungszeichen werden zu Exemplaren der Klasse String.


Hinweis   Weder in der Klasse String noch in StringBuffer existiert ein Konstruktor, der explizit ein char als Parameter zulässt, um aus dem angegebenen Zeichen eine Zeichenkette aufzubauen. Dennoch beschwert sich der Compiler bei new StringBuffer(char) nicht, denn er passt das Zeichen zu einem int an, und es wird der StringBuffer-Konstruktor mit der Längenangabe als Parameter aufgerufen. Dieser besorgt dann Speicherplatz für die angegebene Anzahl Elemente, etwa bei einem »*« Platz für 42 Zeichen, da 42 der ASCII-Code des Zeichens * ist. Zu allem Überfluss enthält das resultierende Objekt statt des Sternchens nur die leere Zeichenreihe. (Leer heißt \0 und nicht Leerzeichen.) Korrekt ist daher nur Folgendes für ein Zeichen c:


StringBuffer s = new StringBuffer( "" + c );

Eine andere Variante ist:


StringBuffer s = new StringBuffer().append( c );


Galileo Computing

4.2.2 Die Länge eines StringBuffer-Objekts lesen und setzen  downtop

Wie bei einem String lässt sich die Länge, die Anzahl der enthaltenen Zeichen, mit der Methode length() erfragen. StringBuffer-Objekte haben jedoch auch eine interne Puffergröße, die sich mit capacity() erfragen lässt und im Konstruktor wie beschrieben festgelegt wird. In diesem Puffer, der, genauer gesagt, ein Array vom Typ char ist, werden die Veränderungen wie Ausschneiden oder Anhängen von Zeichen vorgenommen. Während length() die Anzahl der Zeichen angibt, ist capacity() immer größer oder gleich length() und sagt etwas darüber aus, wie viele Zeichen der Puffer noch aufnehmen kann, ohne dass intern ein neues, größeres Feld benötigt würde:


StringBuffer sb = new StringBuffer( "Blub" );
int length   = sb.  length()  ;        // 4
int capacity = sb.  capacity()  ;      // 20

So ergibt sb.length() 4, aber sb.capacity() ergibt 4 + 16 = 20.

Die Startgröße sollte mit der erwarteten Größe initialisiert werden, um späteres teures internes Vergrößern zu vermeiden. Falls der StringBuffer einen großen internen Puffer hat, aber auf lange Sicht nur wenig Zeichen besitzt, lässt er sich mit trimToSize() auf eine kleinere Größe schrumpfen.

Ändern der Länge

Soll der StringBuffer mehr Daten aufnehmen, so ändert setLength() die Länge auf eine angegebene Anzahl von Zeichen. Der Parameter ist die neue Länge. Ist sie kleiner als length(), so wird der Rest der Zeichenkette einfach abgeschnitten. Die Größe des internen Puffers ändert sich dadurch nicht. Ist setLength() größer, so vergrößert sich der Puffer und die Methode füllt die übrigen Zeichen mit Nullzeichen ’\0’ auf. Die Methode ensureCapacity() fordert, dass der interne Puffer für eine bestimmte Anzahl von Zeichen ausreicht. Wenn nötig, legt sie ein neues, vergrößertes char-Array an, verändert aber nicht die Zeichenfolge, die durch das StringBuffer-Objekt repräsentiert wird.


Galileo Computing

4.2.3 Daten anhängen  downtop

Die häufigste Anwendung von StringBuffer-Objekten ist das Zusammenfügen von Texten aus Daten unterschiedlichen Typs. Dazu definiert StringBuffer eine Reihe von append()-Methoden, die mit unterschiedlichen Datentypen überladen sind.

gp  StringBuffer append( boolean b )
gp  StringBuffer append( char c )
gp  StringBuffer append( char str[] )
gp  StringBuffer append( char str[], int offset, int len )
gp  StringBuffer append( CharSequence s )
gp  StringBuffer append( CharSequence s, int srcOffset, int len )
gp  StringBuffer append( double d )
gp  StringBuffer append( float f )
gp  StringBuffer append( int I )
gp  StringBuffer append( long lng )
gp  StringBuffer append( Object obj )
gp  StringBuffer append( String str )
gp  StringBuffer append( StringBuffer sb )

Besonders nützlich ist in der Praxis append(CharSequence, int, int), da sich auf diese Weise Teile von String-, StringBuffer- und StringBuilder-Objekten anhängen lassen.

Jede append()-Methode verändert den StringBuffer und liefert als Rückgabewert noch eine Referenz darauf zurück. Das hat den großen Vorteil, dass sich Aufrufe der append()-Methoden einfach hintereinander setzen (kaskadieren) lassen:


StringBuffer sb = new StringBuffer( "George Peppard" );
  append(’,’).append("Mr. T,").append("Dirk Benedict,").append("
Dwight Schultz");  

Die Methode append() hängt immer an das Ende an und vergrößert den internen Platz – das interne char-Feld –, falls es nötig ist. Ein neues StringBuffer-Objekt wird nicht erzeugt.


Galileo Computing

4.2.4 Zeichen(folgen) setzen, erfragen, löschen und umdrehen  toptop

Die bekannten Anfrage-Methoden aus String finden wir auch beim StringBuffer wieder. So verhalten sich charAt() und getChars() bei Exemplaren beider Klassen identisch. Neu ist setCharAt(), da in einem StringBuffer Zeichen verändert werden können.


Beispiel   Ändere das erste Zeichen im StringBuffer in einen Großbuchstaben:

StringBuffer sb = new StringBuffer("Wer zu spät kommt, 
den bestraft das Leben"4 );
char c = Character.toUpperCase( sb.charAt(0) );
sb.  setCharAt  ( 0, c );

Der erste Parameter steht für die Position des zu setzenden Zeichens.


Auch substring(int start) und substring(int start, int end) sind aus der Klasse String bekannt. Eine Folge von Zeichen lässt sich durch delete(int start, int end) löschen. deleteCharAt (int index) löscht nur ein Zeichen. In beiden Fällen wird ein inkorrekter Index durch eine StringIndexOutOfBoundsException bestraft. Die Methode replace(int start, int end, String str) löscht zuerst die Zeichen zwischen start und end und fügt anschließend den neuen String str ab start ein. Dabei sind die Endpositionen wie immer exklusiv, das heißt, sie geben das erste Zeichen hinter dem zu verändernden Ausschnitt an. Die Methode insert(int offset, Typ) fügt die Zeichenketten-Repräsentation eines Werts vom Typ Typ an die Stelle offset ein. Sie ähnelt der überladenen append()-Methode. Für char-Arrays existiert insert() in einer abgewandelten Art: insert(int index, char str[], int offset, int len). Es wird nicht das komplette Array in den StringBuffer übernommen, sondern nur ein Ausschnitt:

StringBuffer s = new StringBuffer( "Sub-Etha-Sens-O-Matic" );
int val = 15;
s.  insert  ( 3, val );

Eine weitere Methode reverse() dreht die Zeichenfolge um.


Beispiel   Teste, ob der String s ein Palindrom ist. Palindrome lesen sich von vorne genauso wie von hinten, etwa OTTO.

boolean isPalindrom = new StringBuffer(s).  reverse()  .toString().equals(s);

Bei einem Palindrom mit gemischter Groß-/Kleinschreibung – etwa »Rentner« – muss der Vergleich mit equalsIgnoreCase() gemacht werden.







1   Sagte Michael Gorbatschow anlässlich des 40. Jahrestags der DDR zu Erich Honecker.

2   Mehr deutsche Palindrome gibt es unter http://www.gnudung.de/kram/sprache/palindrom.htm. Eine Liste mit englischen Palindromen, Anagrammen und Verweisen auf andere Seiten gibt es unter http://www.palindromes.org/.





Copyright © Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de