4.2 Strings und deren Anwendung 

Ein String ist eine Sammlung von Zeichen, die die Laufzeitumgebung geordnet im Speicher ablegt. Die Zeichen sind einem Zeichensatz entnommen, der in Java dem 16-Bit-Unicode-Standard entspricht – mit etwas Umwegen ist auch Unicode 4 mit 32-Bit-Zeichen möglich. Wenn ein einzelnes Zeichen in einer Variablen vom Typ char gespeichert werden kann, können Zeichenfolgen in einem char-Feld gehalten werden. Wollten wir Zeichenfolgen selbstständig in Feldern verwalten, ist das mühselig, da wir uns um viele Dinge selbst kümmern müssten, etwa um die Verschiebung der Zeichen beim Löschen und Einfügen in der Mitte, um die Verwaltung des Puffers und vieles mehr.
Java sieht drei Klassen vor, die Zeichenfolgen von der Implementierung abstrahieren. Die Klassen entsprechen der idealen Umsetzung der objektorientierten Idee (mit der wir uns in Kapitel 6 intensiv auseinander setzen): Die Daten sind gekapselt, das heißt, die tatsächliche Zeichenkette ist in der Klasse als privates Feld gegen Zugriffe von außen gesichert, und selbst die Länge ist ein privates Attribut der Klasse, die nur über eine Methode zugänglich ist.
- Die Klasse String repräsentiert nicht änderbare Zeichenketten. Allgemein heißen Objekte, deren Zustand sich nicht verändern lässt, immutable; der Typ String ist ein Beispiel einer solchen immutable-Klasse. Mit Objekten vom Typ String lässt sich nach Zeichen oder Teilzeichenketten suchen, ein String lässt sich mit einem anderen String vergleichen, aber Zeichen im String können nicht verändert werden. Es gibt einige Methoden, die scheinbar Veränderungen an Strings vornehmen, aber sie erzeugen in Wahrheit neue String-Objekte, die die veränderten Zeichenreihen repräsentieren. So entsteht beim Aneinanderhängen zweier String-Objekte als Ergebnis ein drittes String-Objekt für die zusammengefügte Zeichenreihe.
- Die Klassen StringBuffer und StringBuilder repräsentieren im Gegensatz zu String dynamische, beliebig änderbare Zeichenreihen. Der Unterschied zwischen StringBuffer und StringBuilder ist lediglich, dass StringBuffer vor nebenläufigen Operationen geschützt ist, während das auf StringBuilder nicht zutrifft.
Die Entwickler von Java haben eine Symbiose zwischen dem String als Objekt und dem String als eingebauter Datentyp vorgenommen. Die Sprache ermöglicht zwar die direkte Konstruktion von String-Objekten etwa aus String-Literalen (Zeichenketten in doppelten Anführungszeichen) und die Konkatenation (Aneinanderreihung von Strings mit +) von mehreren Strings, doch intern ist die Aneinanderreihung über Methoden der Klassen String, StringBuffer beziehungsweise StringBuilder realisiert. Mit dem Plus auf String-Objekten ist also ein besonderer Operator auf der Klasse String definiert, der nicht eigenständig auf anderen Klassen definiert werden kann. Java unterstützt keine überladenen Operatoren für Klassen, und dieses Plus ist ein Abweichler.
4.2.1 String-Literale als String-Objekte für konstante Zeichenketten 

Damit wir Zeichenketten nutzen können, muss ein Objekt der Klasse String oder StringBuffer/StringBuilder erzeugt worden sein. Nutzen wir String-Literale, so müssen wir die String-Objekte nicht immer von Hand mit new erzeugen, denn ein Ausdruck in doppelten Anführungszeichen ist schon automatisch ein String-Objekt. Das bedeutet auch, dass hinter dem String-Literal gleich ein Punkt für den Methodenaufruf stehen kann.
|
Strings im Konstantenpool
Die JVM erzeugt für jedes Zeichenketten-Literal automatisch ein entsprechendes String-Objekt. Das geschieht für jede konstante Zeichenkette höchstens einmal, egal wie oft sie im Programmverlauf benutzt wird und welche Klassen den String nutzen. Dieses String-Objekt lebt in einem Bereich, der Konstantenpool genannt wird.
System.out.println( "tutego" ); in einer anderen Java-Klassen-Datei steht als int len = "tutego".length(); |
Bei konstanten Werten führt der Compiler Optimierungen durch, etwa in der Art, dass er konstante Ausdrücke gleich berechnet. Nicht nur setzt er für Ausdrücke wie 1 + 2 das Ergebnis 3 ein, auch aufgebrochene konstante String-Teile, die mit Plus konkateniert werden, fügt der Compiler zu einer Zeichenkette zusammen.
String s = "Operating systems are like underwear – nobody really wants to look at them. (Bill Joy)"; String s = "Operating systems are like underwear – nobody really wants to look at them" + '.' + " (Bill Joy)"; |
4.2.2 String-Länge und Test auf Leerstring 

String-Objekte verwalten intern die Zeichenreihe, die sie repräsentieren, und bieten eine Vielzahl von Methoden, um die Eigenschaften des Objekts preiszugeben. Eine Methode haben wir schon benutzt: length(). Für String-Objekte ist diese so implementiert, dass die Anzahl der Zeichen im String (die Länge des Strings) zurückgegeben wird.
Um herauszufinden, ob der String keine Zeichen hat, lässt sich neben length() == 0 auch die Methode isEmpty() nutzen.
4.2.3 Nach enthaltenen Zeichen und Zeichenfolgen suchen 

Die Objektmethode contains(CharSequence) testet, ob ein Teilstring (engl. substring) in der Zeichenkette vorkommt, und liefert true, wenn das der Fall ist. CharSequence ist unter anderem die gemeinsame Schnittstelle von String, StringBuffer und StringBuilder.
if ( s.contains( "Viagra" ) )
... |
Fundstelle mit indexOf() zurückgeben
Die Methode contains() ist nicht mit einem char überladen, kann also nicht nach einem einzelnen Zeichen suchen, es sei denn, der String bestünde nur aus einem Zeichen. Dazu ist indexOf() in der Lage: Die Methode liefert die Fundstelle eines Zeichens beziehungsweise Teilstrings. Findet indexOf() nichts, liefert sie –1.
String s = "Ernest Gräfenberg"; int index1 = s.indexOf( 'e' ); // 3 int index2 = s.indexOf( 'e', index1 + 1 ); // 11 Die Belegung von index1 ist 3, da an der Position 3 das erste Mal ein »e« vorkommt. Die zweite Methode indexOf() sucht mit dem zweiten Ausdruck index1 + 1 ab der Stelle 4 weiter. Das Resultat ist 11. |
Wie contains() unterscheidet die Suche zwischen Groß- und Kleinschreibung. Die Zeichen in einem String sind wie Array-Elemente ab 0 durchnummeriert. Ist der Index kleiner 0, so wird dies ignoriert und automatisch auf 0 gesetzt.
if ( "\b\t\n\f\r\"\\".indexOf(c) >= 0 ) {
...
} contains() konnten wir nicht verwenden, da der Parametertyp nur CharSequence, aber kein char ist. |
Die indexOf()-Methode ist nicht nur mit char parametrisiert, sondern auch mit String (CharSequence wäre vielleicht sinnvoller, da kämen dann etwa noch StringBuffer/StringBuilder dazu).
String str = "In Deutschland gibt es immer noch ein Ruhrgebiet, " +
"obwohl es diese Krankheit schon lange nicht mehr geben soll.";
String s = "es";
int index = str.indexOf( s, str.indexOf(s) + 1 ); // 57 Die nächste Suchposition wird ausgehend von der alten Finderposition errechnet. Das Ergebnis ist 57, da dort zum zweiten Mal das Wort »es« auftaucht. |
Vom Ende an suchen
Genauso wie am Anfang gesucht werden kann, ist es auch möglich, am Ende zu beginnen.
String str = "Gary Schubach";
int index = str.lastIndexOf( 'a' ); // 10 Genauso wie bei indexOf() existiert eine überladene Version, die rückwärts ab einer bestimmten Stelle nach dem nächsten Vorkommen von »a« sucht. Wir schreiben: index = str.lastIndexOf( 'a', index – 1 ); // 1 |
Die Parameter der char-orientierten Methoden indexOf() und lastIndexOf() sind alle vom Typ int und nicht, wie man spontan erwarten könnte, vom Typ char und int. Das zu suchende Zeichen wird als erstes int-Argument übergeben. Die Umwandlung des char in ein int nimmt der Java-Compiler automatisch vor, so dass dies nicht weiter auffällt. Bedauerlicherweise kann es dadurch aber zu Verwechslungen bei der Reihenfolge der Argumente kommen: Bei s.indexOf(start, c) wird der erste Parameter start als Zeichen interpretiert und das gewünschte Zeichen c als Startposition der Suche.
Anzahl Teilstrings einer Zeichenkette
Bisher bietet die Java-Bibliothek keine Funktion, um die Anzahl Teilstrings einer Zeichenkette herauszufinden. Eine solche Funktion ist jedoch schnell geschrieben:
Listing 4.2 CountMatches.java, frequency()
public static int frequency( String source, String part ) { if ( source == null || source.isEmpty() || part == null || part.isEmpty() ) return 0; int count = 0; for ( int pos = 0; (pos = source.indexOf( part, pos )) != –1; count++ ) pos += part.length(); return count; }
4.2.4 Gut, dass wir verglichen haben 

Um Strings zu vergleichen, gibt es viele Möglichkeiten und Optionen. Zunächst sind da equals() für absolute Übereinstimmung und equalsIgnoreCase() für einen Vergleich, der unabhängig von der Groß-/Kleinschreibung ist. Ob ein String mit einem Wort beginnt oder endet, sagen startsWith() und endsWith(). Zum Vergleichen von Teilen gibt es regionMatches(), eine Funktion, die auch unabhängig von der Groß-/Kleinschreibung arbeiten kann.
equals() und equalsIgnoreCase()
Als Erstes gibt es die aus der Klasse Object geerbte und in der Klasse String überschriebene Methode equals(). Die Methode gibt true zurück, falls die Strings gleich lang sind und Zeichen für Zeichen übereinstimmen.
|
equals() beachtet beim Vergleich die Groß- und Kleinschreibung. Mit equalsIgnoreCase() bietet die Java-Bibliothek eine zusätzliche Funktion, um Zeichenketten ohne Beachtung der Groß-/Kleinschreibung zu vergleichen.
String str = "REISEPASS"; boolean result1 = str.equals( "Reisepass" ); // false boolean result2 = str.equalsIgnoreCase( "ReISePaSs" ); // true |
Lexikographische Vergleiche mit Größer/kleiner-Relation
Wie equals() und equalsIgnoreCase() vergleichen auch die Methoden compareTo(String) und compareToIgnoreCase(String) zwei Strings. Nur ist der Rückgabewert von compareTo() kein boolean, sondern ein int. Das Ergebnis signalisiert, ob das Argument lexikografisch kleiner oder größer als das String-Objekt ist beziehungsweise mit diesem übereinstimmt. Das ist zum Beispiel in einer Sortierfunktion wichtig. Der Sortieralgorithmus muss beim Vergleich zweier Strings wissen, wie sie einzusortieren sind.
"Justus".compareTo( "Bob" ) > 0 //"Justus" ist lexikografisch größer als "Bob" "Justus".compareTo( "Justus" ) == 0 "Justus".compareTo( "Peter" ) < 0 |
Der von compareTo() vorgenommene Vergleich basiert nur auf der internen numerischen Kodierung der Unicode-Zeichen. Die Vergleichsfunktion berücksichtigt nicht die landestypischen Besonderheiten, etwa die übliche Behandlung der deutschen Umlaute. Dafür müssten wir Collator-Klassen nutzen, die später in diesem Kapitel vorgestellt werden.
compareToIgnoreCase() ist vergleichbar mit equalsIgnoreCase(), bei der die Groß-/Kleinschreibung keine Rolle spielt. Sun implementiert das mit einem Comparator, der zwei beliebige Objekte – für Zeichenketten natürlich vom Typ String – in eine Reihenfolge bringt. Der Vergleicher ist auch für uns zugänglich.
Endet der String mit ..., beginnt er mit ...
Interessiert uns, ob der String mit einer bestimmten Zeichenfolge beginnt (wir wollen dies »Präfix« nennen), so rufen wir die startsWith()-Methode auf. Eine ähnliche Funktion gibt es für Suffixe: endsWith(). Sie überprüft, ob ein String mit einer Zeichenfolge am Ende übereinstimmt.
String url = "www.tutego.com"; boolean isCom = url.endsWith( ".com" ); // true boolean isHttp = "http://tutego.com".startsWith( "http" ); // true |
String-Teile mit regionMatches() vergleichen
Eine Erweiterung der Ganz-oder-gar-nicht-Vergleichsfunktionen bietet die Methode regionMatches(), mit der Teile einer Zeichenkette mit Teilen einer anderen verglichen werden können. Nimmt das erste Argument von regionMatches() den Wahrheitswert true an, dann spielt die Groß-/Kleinschreibung keine Rolle – damit lässt sich dann auch ein startsWith() und endsWith() mit Vergleichen unabhängig von Groß-/Kleinschreibung durchführen. Der Rückgabewert ist wie bei equalsXXX() ein boolean.
String s = "Deutsche Kinder sind zu dick";
boolean b = s.regionMatches( 9, "Bewegungsarmut bei Kindern", 19, 6 ); |
Die Methode beginnt den Vergleich am neunten Zeichen, also bei »K« im String s und dem 19. Buchstaben in dem Vergleichsstring, ebenfalls ein »K«. Dabei beginnt die Zählung der Zeichen wieder bei 0. Ab diesen beiden Positionen werden sechs Zeichen verglichen. Im Beispiel ergibt der Vergleich von »Kinder« und »Kinder« dann true.
s.regionMatches( true, 9, "Bewegungsarmut bei Kindern", 19, 6 ); |
4.2.5 String-Teile extrahieren 

Die vielleicht wichtigste Funktion der Klasse String ist charAt(int index). Diese Methode liefert das entsprechende Zeichen an einer Stelle, die »Index« genannt wird. Dies bietet eine Möglichkeit, die Zeichen eines Strings (zusammen mit der Methode length()) zu durchlaufen. Ist der Index kleiner null oder größer beziehungsweise gleich der Anzahl der Zeichen im String, so löst die Methode eine StringIndexOutOfBoundsException [Mit 31 Zeichen gehört dieser Methodenname schon zu den längsten. Übertroffen wird er aber noch um 5 Zeichen von TransformerFactoryConfigurationError. Im Spring-Paket gibt es aber JdbcUpdateAffectedIncorrectNumberOfRowsException – auch nicht von schlechten Eltern. ] mit der Fehlerstelle aus.
String s = "Ich bin nicht dick! Ich habe nur weiche Formen."; char first = s.charAt( 0 ); // 'I' char last = s.charAt( s.length() – 1 ); // '.' |
Wir müssen bedenken, dass die Zählung wieder bei 0 beginnt. Daher müssen wir von der Länge des Strings eine Stelle abziehen. Da der Vergleich auf den korrekten Bereich bei jedem Zugriff auf charAt() stattfindet, ist zu überlegen, ob der String bei mehrmaligem Zugriff nicht stattdessen einmalig in ein eigenes Zeichen-Array kopiert werden sollte.
Teile eines Strings als String mit substring()
Wollen wir einen Teilstring aus der Zeichenkette erfragen, so greifen wir zur Methode substring(). Sie existiert in zwei Varianten – beide liefern ein neues String-Objekt zurück, das dem gewünschten Ausschnitt des Originals entspricht.
String s1 = "Infiltration durch Penetration";
String s2 = s1.substring( 19 ); // Penetration |
Der Index von substring(int) gibt die Startposition (null-basiert) an, ab der Zeichen in die neue Teilzeichenkette kopiert werden. substring(int) liefert den Teil von diesem Zeichen bis zum Ende des ursprünglichen Strings – es ergibt s.substring(0) gleich s.
Wollten wir die Teilzeichenkette genauer spezifizieren, so nutzen wir die zweite Variante substring(int,int). Ihre Argumente geben den Anfang und das Ende des gewünschten Ausschnitts an:
String träne = "'Jede Träne kitzelt auch die Wange.'";
// 0 6 11
System.out.println( träne.substring( 6, 11 ) ); // Träne Während die Startposition inklusiv ist, ist die Endposition exklusiv. Das heißt, bei der End-position gehört das Zeichen nicht mehr zur Teilzeichenkette. |
Die Methode substring(int) ist nichts anderes als eine Spezialisierung von substring(int, int), denn die erste Variante mit dem Startindex lässt sich auch als s.substring(beginIndex, s.length()) schreiben.
Selbstverständlich kommen nun diverse Indexüberprüfungen hinzu – eine StringIndexOutOfBoundsException meldet fehlerhafte Positionsangaben wie bei charAt().
Mit getChars() Zeichenfolgen als Array aus dem String extrahieren
Während charAt() nur ein Zeichen liefert, kopiert getChars() mehrere Zeichen aus einem angegebenen Bereich des Strings in ein übergebenes Feld.
String s = "Blasiussegen";
char[] chars = new char[ 5 ];
int srcBegin = 7;
s.getChars( srcBegin, srcBegin + 5, chars, 0 );
System.out.println( new String(chars) ); // segen s.getChars() kopiert ab Position 7 aus dem String s 5 Zeichen in die Elemente des Arrays chars. Das erste Zeichen aus dem Ausschnitt steht dann in chars[0]. |
Die Methode getChars() muss natürlich wieder testen, ob die gegebenen Argumente im grünen Bereich liegen. Das heißt, ob der Startwert nicht < 0 ist und ob der Endwert nicht über die Größe des Strings hinausgeht. Passt das nicht, löst die Methode eine StringIndexOutOfBoundsException aus. Liegt zudem der Startwert hinter dem Endwert, gibt es ebenfalls eine StringIndexOutOfBoundsException, die anzeigt, wie groß die Differenz der Positionen ist. Am besten ist es, die Endposition aus der Startposition zu berechnen, wie es im obigen Beispiel geschehen ist. Passen alle Zeichen in das Feld, kopiert die Implementierung der Methode getChars() mittels System.arraycopy() die Zeichen aus dem internen Array des String-Objekts in das von uns angegebene Ziel.
Möchten wir den kompletten Inhalt eines Strings als ein Array von Zeichen haben, so können wir die Methode toCharArray() verwenden. Intern arbeitet die Methode auch mit getChars(). Als Ziel-Array legt toCharArray() nur ein neues Array an, das wir dann zurückbekommen.
4.2.6 Strings anhängen, Groß-/Kleinschreibung und Leerraum 

Obwohl String-Objekte selbst unveränderlich sind, bietet die Klasse String Methoden an, die aus einer Zeichenkette Teile herausnehmen oder ihr Teile hinzufügen. Diese Änderungen werden natürlich nicht am String-Objekt vorgenommen, sondern die Methode liefert eine Referenz auf ein neues String-Objekt mit verändertem Inhalt zurück.
Anhängen an Strings
Eine weitere Methode erlaubt das Anhängen von Teilen an einen String. Wir haben dies schon öfters mit dem Plus-Operator realisiert. Die Methode von String dazu heißt concat(String). Wir werden später sehen, dass es die StringBuffer/StringBuilder-Klassen noch weiter treiben und eine überladene Methode append() mit der gleichen Funktionalität anbieten. Das steckt auch hinter dem Plus-Operator. Der Compiler wandelt dies automatisch in eine Kette von append()-Aufrufen um.
String s1 = "Das aktuelle Datum ist: ";
String s2 = new Date().toString();
String s3 = s1.concat( s2 ); // Das aktuelle Datum ist: Tue Jun 05 14:46:41 CEST 2005 |
Die concat()-Methode arbeitet relativ zügig und effizienter als der Plus-Operator, der einen temporären String-Puffer anlegt. Doch mit dem Plus-Operator ist es hübscher anzusehen. (Aber wie das so ist: Sieht nett aus, aber ...)
String s3 = "Das aktuelle Datum ist: " + new Date().toString(); Es geht sogar noch kürzer, denn der Plus-Operator ruft automatisch toString() bei Objekten auf: String s3 = "Das aktuelle Datum ist: " + new Date(); |
concat() legt ein internes Feld an, kopiert die beiden Zeichenreihen per getChars() hinein und liefert mit einem String-Konstruktor die resultierende Zeichenkette.
Groß-/Kleinschreibung
Die Klasse Character deklariert einige statische Methoden, um einzelne Zeichen in Groß-/Kleinbuchstaben umzuwandeln. Die Schleife, die das für jedes Zeichen übernimmt, können wir uns sparen, denn dazu gibt es die Methoden toUpperCase() und toLowerCase() in der Klasse String. Interessant ist an beiden Methoden, dass sie einige sprachabhängige Feinheiten beachten. So zum Beispiel, dass es im Deutschen kein großes »ß« gibt, denn »ß« wird zu »SS«. Gammelige Textverarbeitungen bekommen das manchmal nicht auf die Reihe, und im Inhaltsverzeichnis steht dann so etwas wie »SPAß IN DER NAßZELLE«. Aber bei möglichen Missverständnissen müsste »ß« auch zu »SZ« werden, vergleiche »SPASS IN MASZEN« mit »SPASS IN MASSEN« (ein ähnliches Beispiel steht im Duden). Diese Umwandlung ist aber nur von Klein nach Groß von Bedeutung. Für beide Konvertierungsrichtungen gibt es jedoch im Türkischen Spezialfälle, bei denen die Zuordnung zwischen Groß- und Kleinbuchstaben von der Festlegung in anderen Sprachen abweicht.
String s1 = "Spaß in der Naßzelle.";
String s2 = s1.toLowerCase().toUpperCase(); // SPASS IN DER NASSZELLE.
System.out.println( s2.length() – s1.length() ); // 2 |
Das Beispiel dient zugleich als Warnung, dass sich im Fall von »ß« die Länge der Zeichenkette vergrößert. Das kann zu Problemen führen, wenn vorher Speicherplatz bereitgestellt wurde. Dann könnte die neue Zeichenkette nicht mehr in den Speicherbereich passen. Arbeiten wir nur mit String-Objekten, haben wir dieses Problem glücklicherweise nicht. Aber berechnen wir etwa für einen Texteditor die Darstellungsbreite einer Zeichenkette in Pixel auf diese Weise, dann sind Fehler vorprogrammiert.
Um länderspezifische Besonderheiten zu berücksichtigen, lassen sich die toXXXCase()-Methoden zusätzlich mit einem Locale-Objekt füttern. (Wir gehen im Kapitel 10 auf Sprachumgebungen und die Klasse Locale ein.) Die parameterlosen Methoden wählen die Sprachumgebung gemäß den Länder-Einstellungen des Betriebssystems:
public String toLowerCase() { return toLowerCase( Locale.getDefault() ); }
Ähnliches steht bei toUpperCase().
Leerraum entfernen
In einer Benutzereingabe oder Konfigurationsdatei steht nicht selten vor oder hinter dem wichtigen Teil eines Texts Leerraum wie Leerzeichen oder Tabulatoren. Vor der Bearbeitung sollten sie entfernt werden. Die String-Klasse bietet dazu trim() an. Diese Methode entfernt Leer- und ähnliche Füllzeichen am Anfang und Ende eines Strings. Andere Modesprachen wie Visual Basic bieten dazu noch trim()-Funktionen an, die nur die Leerzeichen vorher oder nachher verwerfen. Die Java-Bibliothek bietet das so einfach nicht. [Wieder ein Hinweis, dass Visual Basic einfach die bessere Sprache ist ... ]
4.2.7 Suchen und ersetzen 

Da String-Objekte unveränderlich sind, kann eine Veränderungsfunktion nur einen neuen String mit den Veränderungen zurückgeben. Wir finden in Java vier Funktionen, die suchen und ersetzen:
- replace(char oldChar, char newChar). Ersetzt einzelne Zeichen.
- replace( CharSequence target, CharSequence replacement). Ersetzt eine Zeichenkette durch eine andere Zeichenkette.
- replaceAll( String regex, String replacement). Ersetzt alle Strings, die durch einen regulären Ausdruck beschrieben werden.
- replaceFirst( String regex, String replacement). Ersetzt den ersten String, der durch einen regulären Ausdruck beschrieben wird.
Ersetzen ohne reguläre Ausdrücke
Die replace(char, char)-Methode ersetzt einzelne Zeichen.
String s1 = "Honolulu";
String s2 = s1.replace( 'o', 'u' ); // s2 = "Hunululu" Das String-Objekt mit dem Namen s1 wird selbst nicht verändert. Es wird nur ein neues String-Objekt mit dem Inhalt »Hunululu« erzeugt und von replace() zurückgegeben. |
Gibt es etwas zu ersetzen, erzeugt replace() intern ein neues Zeichenfeld, führt die Ersetzungen durch und konvertiert das interne Zeichenfeld in ein String-Objekt, was die Rückgabe ist. Gab es nichts zu ersetzen, bekommen wir das gleiche String-Objekt zurück, das die Anfrage stellte. Die replace()-Methode ersetzt immer alle Zeichen. Eine Variante, die nur das erste Zeichen ersetzt, müssen wir uns selbst schreiben.
Eine zweite überladene Variante replace(CharSequence, CharSequence) sucht nach allen auftretenden Zeichenfolgen und ersetzt sie durch eine andere Zeichenfolge. Der Ersetzungs-string kann auch leer sein.
String s = "Schnecken erschrecken, wenn Schnecken an Schnecken schlecken, " +
"weil zum Schrecken vieler Schnecken, Schnecken nicht schmecken.";
System.out.println( s.replace("Schnecke", "Katze") ); Das Ergebnis auf dem Bildschirm ist »Katzen erschrecken, wenn Katzen an Katzen schlecken, weil zum Schrecken vieler Katzen, Katzen nicht schmecken.« |
Suchen und ersetzen mit regulären Ausdrücken
Die Funktionen replaceAll() und replaceFirst() suchen in Zeichenketten mit Hilfe von regulären Ausdrücken und nehmen Ersetzungen vor; replaceFirst() ersetzt, wie der Name schon sagt, nur das erste Auftreten. Für ganz allgemeine Ersetzungsaufgaben mit beliebigen Zeichen eignen sich replaceAll() und replaceFirst() nicht; hier ist die replace()-Funktion passend. Weil der Suchstring immer ein regulärer Ausdruck ist, können Sonderzeichen auftauchen, die eine besondere Rolle spielen. So müssen zum Beispiel Dollar oder Punkt mit »\« ausmaskiert werden.
String s; s = "'Tag, Karl.' 'Wie geht's, Karl?' 'Gut, Karl.' 'Kahl, Karl?' 'Ja, Karl, ganz kahl.'"; System.out.println( s.replace(".", "!") ); Der Aufruf ersetzt alle Punkte durch Ausrufezeichen, sodass das Ergebnis wie folgt lautet: 'Tag, Karl!' 'Wie geht's, Karl?' 'Gut, Karl!' 'Kahl, Karl?' 'Ja, Karl, ganz kahl!' Nutzen wir s.replaceAll(".", "!"), führt das nicht zum Erfolg, sondern nur zu der Zeichenkette: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
Der Punkt steht in regulären Ausdrücken für beliebige Zeichen. Erst, wenn dieser mit \\ ausmaskiert wird, liefert die Anweisung wie in s.replaceAll("\\.", "!") das gewünschte Ergebnis. Die statische Methode quote() aus der Klasse String nimmt für uns die Ersetzungen vor. Wegen dem Sonderstatus vom »\« muss auch dieses Zeichen selbst ausmaskiert werden.
4.2.8 String-Objekte mit Konstruktoren neu anlegen 

Liegt die Zeichenkette nicht als String-Literal vor, lassen sich mit den unterschiedlichen Konstruktoren der String-Klasse neue String-Objekte aufbauen.
final class java.lang.String
implements CharSequence, Comparable<String>, Serializable |
- String() Erzeugt ein neues Objekt ohne Zeichen (den leeren String »«).
- String( String string ) Erzeugt ein neues Objekt mit einer Kopie von string. Es wird selten benötigt, da String-Objekte unveränderbar (immutable) sind.
- String( char[] value ) Erzeugt ein neues Objekt und kopiert die im char-Feld vorhandenen Zeichen in das neue String-Objekt.
- String( char[] value, int offset, int length ) Erzeugt wie String(char[]) einen String aus einem Ausschnitt eines Zeichenfelds. Der verwendete Ausschnitt beginnt bei dem Index offset und umfasst length-Zeichen.
- String( byte[] bytes ) Erzeugt ein neues Objekt aus dem Bytefeld. Das Byte-Array enthält keine Unicode-Zeichen, sondern eine Folge von Bytes, die nach der Standardkodierung der jeweiligen Plattform in Zeichen umgewandelt werden.
- String( byte[] bytes, int offset, int length ) Erzeugt wie String(byte[]) einen String aus einem Ausschnitt eines Bytefelds.
- String( byte[] bytes, String charsetName ) throws UnsupportedEncodingException Erzeugt einen neuen String von einem Byte-Array mithilfe einer speziellen Zeichenkodierung, die die Umwandlung von Bytes in Unicode-Zeichen festlegt.
- String( byte[] bytes, int offset, int length, String charset ) throws UnsupportedEncodingException Erzeugt einen neuen String mit einem Teil des Byte-Arrays mithilfe einer speziellen Zeichenkodierung.
- String( StringBuffer buffer )
- String( StringBuilder builder ) Erzeugt aus einem veränderlichen StringBuffer-/StringBuilder-Objekt ein unveränderliches String-Objekt, das dieselbe Zeichenreihe repräsentiert.
- String( int[] codePoints, int offset, int count ) Erzeugt ein String-Objekt mit Unicode-Codepoints, die Zeichen über int kodieren.
Die Konstruktoren sind im Speziellen nur dann nötig, wenn aus einer Fremdrepräsentation wie einem StringBuffer, StringBuilder, char[] oder byte[] oder Teilen daraus ein String-Objekt aufgebaut werden soll.
char[] vocalsArray = { 'a', 'e', 'i', 'o', 'u' };
String vocal = new String( vocalsArray ); |
Der Konstruktor String(String)
Ein Konstruktor führt leicht zur Verwirrung, und zwar der Konstruktor, der einen anderen String annimmt. So ergeben die beiden folgenden Zeilen die Referenz auf ein String-Objekt:
String str = "Ehre Rudolf Wijbrand Kesselaar"; String str = new String( "Ehre Rudolf Wijbrand Kesselaar" );
Die zweite Lösung erzeugt unnötigerweise ein zusätzliches String-Objekt, denn das Literal ist ja schon ein vollwertiges String-Objekt.
Der Konstruktor ist nur für eine Optimierung zu gebrauchen. Immer wenn mit substring() ein Teilstring aufgebaut wurde, wird die ganze Zeichenfolge als char-Feld intern referenziert. Um den Speicherbedarf in diesem Fall zu optimieren, ist dieser Konstruktor gut geeignet.
Leerer String, Leer-String oder Null-String
Die Anweisungen
String str = "";
oder
String str = new String();
referenzieren in beiden Fällen String-Objekte, die keine Zeichen enthalten. Die zweite Schreibweise erzeugt aber ein neues String-Objekt, während im ersten Fall das String-Literal im Konstantenpool liegt. Ein String ohne Zeichen nennen wir leeren String, Leer-String oder Null-String. Der letzte Begriff ist leider etwas unglücklich und führt oft zur Verwechslung mit Folgendem:
String s = null; System.out.println( s ); // null
Hier bekommen wir keinen leeren String und bei der Benutzung im Methodenaufruf, etwa bei s.length(), eine NullPointerException.
Strings einer gegebenen Länge erzeugen
An einigen Stellen in den Bibliotheken gibt es noch Nachholbedarf – das gilt insbesondere für die Klasse String. Zum Beispiel gibt es keine Funktion, die eine Zeichenkette einer vorgegebenen Länge aus einem einzelnen Zeichen erzeugt. Selbst einfachste BASIC-Dialekte verfügen über solche Funktionen. In Java müssen wir sie selbst entwickeln.
Zunächst ist zu fragen, ob die Zeichenkette als String oder als StringBuffer/StringBuilder bereitgestellt werden soll. Erwarten wir das Ergebnis als String, können wir erst ein char-Feld aufbauen, das dann mit Arrays.fill() und einem gewünschten Zeichen gefüllt wird. Im zweiten Schritt konvertieren wir das Feld in ein String-Objekt:
Listing 4.3 GenerateStringWithGivenLength.java, generateStringWithLength()
public static String generateStringWithLength( int len, char fill ) { if ( len < 0 ) return null; char[] cs = new char[ len ]; Arrays.fill( cs, fill ); return new String( cs ); }