Java Language
Zeichenketten
Suche…
Einführung
Zeichenfolgen ( java.lang.String
) sind Textstücke, die in Ihrem Programm gespeichert sind. Strings sind in Java kein primitiver Datentyp , in Java-Programmen jedoch sehr häufig.
In Java sind Strings unveränderlich, was bedeutet, dass sie nicht geändert werden können. (Klicken Sie hier, um eine genauere Erklärung der Unveränderlichkeit zu erhalten.)
Bemerkungen
Da Java-Zeichenfolgen unveränderlich sind , geben alle Methoden, die einen String
bearbeiten , ein neues String
Objekt zurück . Sie ändern den ursprünglichen String
. Dazu gehören untergeordnete Zeichenfolgen und Ersetzungsmethoden, von denen C- und C ++ - Programmierer erwarten würden, dass sie das Ziel- String
Objekt mutieren.
Verwenden Sie einen StringBuilder
anstelle von String
wenn Sie mehr als zwei String
Objekte verketten möchten, deren Werte nicht zur Kompilierzeit bestimmt werden können. Diese Technik ist performanter als das Erstellen neuer String
Objekte und deren Verkettung, da StringBuilder
veränderbar ist.
StringBuffer
kann auch verwendet werden, um String
Objekte zu verketten. Diese Klasse ist jedoch weniger leistungsfähig, da sie Thread-sicher ist und vor jeder Operation einen Mutex erhält. Da Sie bei der Verkettung von Strings fast nie Thread-Sicherheit benötigen, sollten Sie am besten StringBuilder
.
Wenn Sie eine Zeichenfolgenverkettung als einen einzelnen Ausdruck ausdrücken können, ist es besser, den Operator +
zu verwenden. Der Java-Compiler konvertiert einen Ausdruck, der +
Verkettungen enthält, in eine effiziente Folge von Vorgängen, wobei entweder String.concat(...)
oder StringBuilder
. Der Hinweis zur Verwendung von StringBuilder
explizit nur, wenn die Verkettung mehrere Ausdrücke enthält.
Speichern Sie vertrauliche Informationen nicht in Zeichenfolgen. Wenn jemand in der Lage ist, einen Speicherauszug Ihrer laufenden Anwendung abzurufen, kann er alle vorhandenen String
Objekte finden und deren Inhalt lesen. Dies umfasst String
Objekte, die nicht erreichbar sind und auf die Garbage Collection warten. Wenn dies ein Problem ist, müssen Sie die sensiblen String-Daten löschen, sobald Sie damit fertig sind. Mit String
Objekten ist dies nicht möglich, da sie nicht veränderbar sind. Daher ist es ratsam, char[]
-Objekte zum Speichern sensibler Zeichendaten zu verwenden und sie zu löschen (z. B. mit '\000'
Zeichen überschreiben), wenn Sie fertig sind.
Alle String
Instanzen werden auf dem Heap erstellt, sogar Instanzen, die String-Literalen entsprechen. Das Besondere an String-Literalen ist, dass die JVM dafür sorgt, dass alle Literale, die gleich sind (dh aus den gleichen Zeichen bestehen), durch ein einzelnes String
Objekt dargestellt werden (dieses Verhalten wird in JLS angegeben). Dies wird von JVM-Klassenladern implementiert. Wenn ein Klassenladeprogramm eine Klasse lädt, sucht es nach String-Literalen, die in der Klassendefinition verwendet werden, und prüft jedes Mal, wenn es einen Eintrag im String-Pool für dieses Literal gibt (das Literal als Schlüssel). . Wenn bereits ein Eintrag für das Literal vorhanden ist, wird der Verweis auf eine String
Instanz verwendet, die als Paar für dieses Literal gespeichert ist. Andernfalls wird eine neue String
Instanz erstellt und ein Verweis auf die Instanz für das Literal (als Schlüssel verwendet) im String-Pool gespeichert. (Siehe auch String Interning ).
Der String-Pool wird im Java-Heap gehalten und unterliegt der normalen Speicherbereinigung.
In Java-Versionen vor Java 7 wurde der String-Pool in einem speziellen Teil des Heap-Speichers gehalten, der als "PermGen" bezeichnet wird. Dieser Teil wurde nur gelegentlich gesammelt.
In Java 7 wurde der String-Pool von "PermGen" verschoben.
Beachten Sie, dass String-Literale implizit von jeder Methode, die sie verwendet, erreichbar sind. Dies bedeutet, dass die entsprechenden String
Objekte nur dann gesammelt werden können, wenn der Code selbst gesammelt wird.
Bis Java 8 werden String
Objekte als ein UTF-16-Char-Array implementiert (2 Byte pro Char). In Java 9 gibt es einen Vorschlag, String
als ein Byte-Array mit einem Codierungsflag-Feld zu implementieren, um zu beachten, ob die Zeichenfolge als Byte (LATIN-1) oder Zeichen (UTF-16) codiert ist.
Zeichenfolgen vergleichen
Um Strings zu vergleichen für Gleichheit, sollten Sie das String - Objekt verwenden equals
oder equalsIgnoreCase
Methoden.
Das folgende Snippet bestimmt beispielsweise, ob die beiden Instanzen von String
für alle Zeichen gleich sind:
String firstString = "Test123";
String secondString = "Test" + 123;
if (firstString.equals(secondString)) {
// Both Strings have the same content.
}
In diesem Beispiel werden sie unabhängig von ihrem Fall verglichen:
String firstString = "Test123";
String secondString = "TEST123";
if (firstString.equalsIgnoreCase(secondString)) {
// Both Strings are equal, ignoring the case of the individual characters.
}
Beachten Sie, dass equalsIgnoreCase
nicht Sie lassen eine angeben Locale
. Wenn Sie beispielsweise die beiden Wörter "Taki"
und "TAKI"
auf Englisch vergleichen, sind sie gleich; In Türkisch sind sie jedoch unterschiedlich (in Türkisch ist das Kleinbuchstabe I
ı
). Für Fälle wie diese, die beiden Strings Umwandlung mit in Kleinbuchstaben (oder Großbuchstaben) Locale
und dann mit den Vergleich equals
ist die Lösung.
String firstString = "Taki";
String secondString = "TAKI";
System.out.println(firstString.equalsIgnoreCase(secondString)); //prints true
Locale locale = Locale.forLanguageTag("tr-TR");
System.out.println(firstString.toLowerCase(locale).equals(
secondString.toLowerCase(locale))); //prints false
Verwenden Sie nicht den Operator ==, um Strings zu vergleichen
Wenn Sie nicht garantieren können, dass alle Zeichenfolgen intern sind (siehe unten), sollten Sie die Operatoren ==
oder !=
Nicht zum Vergleichen von Zeichenfolgen verwenden. Diese Operatoren testen tatsächlich Referenzen, und da mehrere String
Objekte denselben String darstellen können, kann dies zu einer falschen Antwort führen.
Verwenden String.equals(Object)
stattdessen die String.equals(Object)
-Methode, die die String-Objekte basierend auf ihren Werten vergleicht. Eine ausführliche Erklärung finden Sie unter Pitfall: Verwenden Sie ==, um Zeichenfolgen zu vergleichen .
Strings in einer switch-Anweisung vergleichen
Ab Java 1.7 ist es möglich, eine String-Variable mit Literalen in einer switch
Anweisung zu vergleichen. NullPointerException
Sie sicher, dass der String nicht NullPointerException
ist, andernfalls wird immer eine NullPointerException
. Die Werte werden mit String.equals
verglichen, dh die Groß- und Kleinschreibung wird String.equals
.
String stringToSwitch = "A";
switch (stringToSwitch) {
case "a":
System.out.println("a");
break;
case "A":
System.out.println("A"); //the code goes here
break;
case "B":
System.out.println("B");
break;
default:
break;
}
Strings mit konstanten Werten vergleichen
Wenn Sie einen String
mit einem konstanten Wert vergleichen, können Sie den konstanten Wert auf die linke Seite von equals
um sicherzustellen, dass Sie keine NullPointerException
wenn der andere String null
.
"baz".equals(foo)
Während foo.equals("baz")
eine NullPointerException
wenn foo
null
, wird "baz".equals(foo)
zu false
ausgewertet.
Eine besser lesbare Alternative ist die Verwendung von Objects.equals()
, die beide Parameter auf Null überprüft: Objects.equals(foo, "baz")
.
( Anmerkung: Es ist fraglich, ob es besser ist, NullPointerExceptions
generell zu vermeiden oder sie passieren zu lassen und dann die eigentliche Ursache zu beheben; siehe hier und hier . Es ist nicht zu rechtfertigen, die Vermeidungsstrategie als "Best Practice" zu bezeichnen.)
Stringbestellungen
Die String
Klasse implementiert String.compareTo
Comparable<String>
mit der String.compareTo
Methode (wie zu Beginn dieses Beispiels beschrieben). Dadurch wird die natürliche Reihenfolge von String
Objekten zwischen Groß- und Kleinschreibung unterschieden. Die String
Klasse stellt eine Comparator<String>
Konstante Comparator<String>
Namen CASE_INSENSITIVE_ORDER
die für die Sortierung nach Groß- und Kleinschreibung geeignet ist.
Vergleich mit internen Strings
Die Java-Sprachspezifikation ( JLS 3.10.6 ) besagt Folgendes:
„Darüber hinaus ist ein Stringliteral bezieht sich immer auf die gleiche Instanz der Klasse
String
Dies liegt daran , Stringliterale -. Oder, allgemeiner, Strings , die die Werte der konstanten Ausdrücke sind - interniert sind , um eindeutige Instanzen zu teilen, wobei das Verfahren unter Verwendung vonString.intern
. "
Das heißt, es ist sicher, Referenzen auf zwei String- Literale mithilfe von ==
zu vergleichen. Dasselbe gilt für Verweise auf String
Objekte, die mit der Methode String.intern()
.
Zum Beispiel:
String strObj = new String("Hello!");
String str = "Hello!";
// The two string references point two strings that are equal
if (strObj.equals(str)) {
System.out.println("The strings are equal");
}
// The two string references do not point to the same object
if (strObj != str) {
System.out.println("The strings are not the same object");
}
// If we intern a string that is equal to a given literal, the result is
// a string that has the same reference as the literal.
String internedStr = strObj.intern();
if (internedStr == str) {
System.out.println("The interned string and the literal are the same object");
}
Hinter den Kulissen führt der Internierungsmechanismus eine Hashtabelle, die alle intern erreichbaren Zeichenfolgen enthält, die noch erreichbar sind . Wenn Sie intern()
für einen String
aufrufen, sucht die Methode das Objekt in der Hash-Tabelle:
- Wenn der String gefunden wird, wird dieser Wert als interner String zurückgegeben.
- Andernfalls wird der Hashtabelle eine Kopie der Zeichenfolge hinzugefügt, und diese Zeichenfolge wird als interne Zeichenfolge zurückgegeben.
Es ist möglich, Interning zu verwenden, um den Vergleich von Strings mit ==
. Dabei gibt es jedoch erhebliche Probleme. Siehe Pitfall - Interning Strings, sodass Sie == verwenden können, ist eine schlechte Idee für Details. In den meisten Fällen wird dies nicht empfohlen.
Ändern der Groß- / Kleinschreibung von Zeichen in einem String
Der String
Typ bietet zwei Methoden zum Konvertieren von Zeichenfolgen zwischen Groß- und Kleinschreibung:
-
toUpperCase
, um alle Zeichen intoUpperCase
zu konvertieren -
toLowerCase
, um alle Zeichen intoLowerCase
zu konvertieren
Diese Methoden geben beide die konvertierten Zeichenfolgen als neue String
Instanzen zurück. Die ursprünglichen String
Objekte werden nicht geändert, da String
in Java unveränderlich ist. Weitere Informationen zur Unveränderlichkeit finden Sie hier: Unveränderlichkeit von Strings in Java
String string = "This is a Random String";
String upper = string.toUpperCase();
String lower = string.toLowerCase();
System.out.println(string); // prints "This is a Random String"
System.out.println(lower); // prints "this is a random string"
System.out.println(upper); // prints "THIS IS A RANDOM STRING"
Nicht alphabetische Zeichen wie Ziffern und Satzzeichen bleiben von diesen Methoden unberührt. Beachten Sie, dass diese Methoden unter bestimmten Bedingungen auch falsch mit bestimmten Unicode-Zeichen umgehen können.
Hinweis : Diese Methoden sind abhängig vom Gebietsschema und können zu unerwarteten Ergebnissen führen, wenn sie für Zeichenfolgen verwendet werden, die unabhängig vom Gebietsschema interpretiert werden sollen. Beispiele sind Programmiersprachen-IDs, Protokollschlüssel und HTML
Tags.
Beispielsweise gibt "TITLE".toLowerCase()
in einem türkischen Gebietsschema " tıtle
" zurück, wobei ı (\u0131)
der Buchstabe LATIN SMALL LETTER DOTLESS I ist . Locale.ROOT
als Parameter an die entsprechende Methode zur toLowerCase(Locale.ROOT)
z. B. toLowerCase(Locale.ROOT)
oder toUpperCase(Locale.ROOT)
), um korrekte Ergebnisse für toUpperCase(Locale.ROOT)
.
Obwohl die Verwendung von Locale.ENGLISH
für die meisten Fälle auch richtig ist, ist die Sprache , unveränderliche Art und Weise Locale.ROOT
.
Eine detaillierte Liste der Unicode-Zeichen, für die ein spezielles Gehäuse erforderlich ist, finden Sie auf der Website des Unicode Consortium .
Groß- und Kleinschreibung eines bestimmten Zeichens innerhalb einer ASCII-Zeichenfolge ändern:
Um den Fall eines bestimmten Zeichens einer ASCII-Zeichenfolge zu ändern, kann folgender Algorithmus verwendet werden:
Schritte:
- Deklarieren Sie einen String.
- Geben Sie die Zeichenfolge ein.
- Konvertieren Sie die Zeichenfolge in ein Zeichenfeld.
- Geben Sie das Zeichen ein, nach dem gesucht werden soll.
- Suchen Sie nach dem Zeichen im Zeichenfeld.
- Wenn gefunden, überprüfen Sie, ob das Zeichen Klein- oder Großbuchstaben ist.
- Wenn Sie Großbuchstaben verwenden, fügen Sie dem ASCII-Code des Zeichens 32 hinzu.
- Bei Kleinbuchstaben subtrahieren Sie 32 vom ASCII-Code des Zeichens.
- Ändern Sie das ursprüngliche Zeichen aus dem Zeichen-Array.
- Konvertieren Sie das Zeichenarray wieder in die Zeichenfolge.
Voila, der Fall des Charakters wurde geändert.
Ein Beispiel für den Code für den Algorithmus ist:
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the String");
String s = scanner.next();
char[] a = s.toCharArray();
System.out.println("Enter the character you are looking for");
System.out.println(s);
String c = scanner.next();
char d = c.charAt(0);
for (int i = 0; i <= s.length(); i++) {
if (a[i] == d) {
if (d >= 'a' && d <= 'z') {
d -= 32;
} else if (d >= 'A' && d <= 'Z') {
d += 32;
}
a[i] = d;
break;
}
}
s = String.valueOf(a);
System.out.println(s);
Suchen einer Zeichenfolge in einer anderen Zeichenfolge
Um zu überprüfen, ob ein bestimmter String a
in einem String b
oder nicht, können wir die Methode String.contains()
mit folgender Syntax verwenden:
b.contains(a); // Return true if a is contained in b, false otherwise
Die Methode String.contains()
kann verwendet werden, um zu überprüfen, ob eine CharSequence
in der CharSequence
kann. Die Methode sucht nach der Zeichenfolge a
in der Zeichenfolge b
.
String str1 = "Hello World";
String str2 = "Hello";
String str3 = "helLO";
System.out.println(str1.contains(str2)); //prints true
System.out.println(str1.contains(str3)); //prints false
Um die genaue Position zu finden, an der ein String in einem anderen String beginnt, verwenden Sie String.indexOf()
:
String s = "this is a long sentence";
int i = s.indexOf('i'); // the first 'i' in String is at index 2
int j = s.indexOf("long"); // the index of the first occurrence of "long" in s is 10
int k = s.indexOf('z'); // k is -1 because 'z' was not found in String s
int h = s.indexOf("LoNg"); // h is -1 because "LoNg" was not found in String s
Die String.indexOf()
Methode gibt den ersten Index einen char
oder String
in einem anderen String
. Die Methode gibt -1
wenn sie nicht gefunden wird.
Hinweis : Die Methode String.indexOf()
Groß- und Kleinschreibung.
Beispiel für eine Suche, bei der der Fall ignoriert wird:
String str1 = "Hello World";
String str2 = "wOr";
str1.indexOf(str2); // -1
str1.toLowerCase().contains(str2.toLowerCase()); // true
str1.toLowerCase().indexOf(str2.toLowerCase()); // 6
Länge eines Strings ermitteln
Um die Länge eines String
Objekts String
, rufen Sie die length()
-Methode auf. Die Länge entspricht der Anzahl der UTF-16-Codeeinheiten (Zeichen) in der Zeichenfolge.
String str = "Hello, World!";
System.out.println(str.length()); // Prints out 13
Ein char
in einem String ist der UTF-16-Wert. Unicode-Codepunkte mit Werten ≥ 0x1000 (zum Beispiel die meisten Emojis) verwenden zwei Zeichenpositionen. Um die Anzahl der Unicode - Codepoints in einem String zu zählen, unabhängig davon , ob die einzelnen Codepoint passen in einem UTF-16 char
Wert, können Sie die Verwendung codePointCount
Methode:
int length = str.codePointCount(0, str.length());
Sie können ab Java 8 auch einen Stream mit Codepoints verwenden:
int length = str.codePoints().count();
Substrings
String s = "this is an example";
String a = s.substring(11); // a will hold the string starting at character 11 until the end ("example")
String b = s.substring(5, 10); // b will hold the string starting at character 5 and ending right before character 10 ("is an")
String b = s.substring(5, b.length()-3); // b will hold the string starting at character 5 ending right before b' s lenght is out of 3 ("is an exam")
Teilstrings können auch auf das Slice angewendet und Zeichen in den ursprünglichen String eingefügt / ersetzt werden. Beispielsweise haben Sie ein chinesisches Datum gefunden, das chinesische Zeichen enthält, Sie möchten es jedoch als Datumszeichenfolge speichern.
String datestring = "2015年11月17日"
datestring = datestring.substring(0, 4) + "-" + datestring.substring(5,7) + "-" + datestring.substring(8,10);
//Result will be 2015-11-17
Die Teilzeichenfolge- Methode extrahiert ein Stück einer String
. Wenn ein Parameter angegeben wird, ist der Parameter der Anfang und das Teil erstreckt sich bis zum Ende des String
. Wenn zwei Parameter angegeben werden, ist der erste Parameter das Startzeichen und der zweite Parameter der Index des Zeichens direkt nach dem Ende (das Zeichen am Index ist nicht enthalten). Eine einfache Möglichkeit zur Überprüfung besteht darin, dass die Subtraktion des ersten Parameters vom zweiten Parameter die erwartete Länge der Zeichenfolge ergibt.
In JDK <7u6 Versionen der substring
Methode instanziiert ein String
, der die gleiche Unterstützung teilt char[]
wie das Original String
und hat die interne offset
und count
Felder auf dem Ergebnis Start und Länge. Eine solche gemeinsame Nutzung kann zu Speicherverlusten führen, die verhindert werden können, indem der new String(s.substring(...))
, um die Erstellung einer Kopie zu erzwingen. new String(s.substring(...))
kann char[]
Speicherbereinigung erhalten.
Von JDK 7u6 der substring
Methode immer kopiert die gesamte zugrunde liegende char[]
Array, so dass die Komplexität linear im Vergleich zum vorherigen konstant einem , sondern das Fehlen von Speicherlecks in der gleichen Zeit zu gewährleisten.
Das n-te Zeichen in einem String abrufen
String str = "My String";
System.out.println(str.charAt(0)); // "M"
System.out.println(str.charAt(1)); // "y"
System.out.println(str.charAt(2)); // " "
System.out.println(str.charAt(str.length-1)); // Last character "g"
Um die n - te Zeichen in einer Zeichenfolge zu erhalten, rufen Sie einfach charAt(n)
auf einem String
, wobei n
der Index des Zeichens möchten Sie abrufen
HINWEIS: Der Index n
beginnt bei 0
, das erste Element befindet sich also bei n = 0.
Plattformunabhängiges neues Trennzeichen
Da das neue Zeilentrennzeichen von Plattform zu Plattform variiert (z. B. \n
bei Unix-ähnlichen Systemen oder \r\n
bei Windows), ist häufig ein plattformunabhängiger Zugriff erforderlich. In Java kann es von einer Systemeigenschaft abgerufen werden:
System.getProperty("line.separator")
Da das neue Zeilentrennzeichen so häufig benötigt wird, steht in Java 7 eine Verknüpfungsmethode zur Verfügung, die genau das gleiche Ergebnis wie der obige Code zurückgibt:
System.lineSeparator()
Hinweis : Da es sehr unwahrscheinlich ist, dass sich das neue Zeilentrennzeichen während der Programmausführung ändert, ist es eine gute Idee, es in einer statischen Endvariablen zu speichern, anstatt es jedes Mal, wenn es benötigt wird, aus der Systemeigenschaft abzurufen.
Wenn Sie String.format
, verwenden Sie %n
anstelle von \n
oder '\ r \ n', um ein plattformunabhängiges neues Trennzeichen für Zeilen auszugeben.
System.out.println(String.format('line 1: %s.%nline 2: %s%n', lines[0],lines[1]));
Hinzufügen der toString () - Methode für benutzerdefinierte Objekte
Angenommen, Sie haben die folgende Person
definiert:
public class Person {
String name;
int age;
public Person (int age, String name) {
this.age = age;
this.name = name;
}
}
Wenn Sie ein neues Person
instanziieren:
Person person = new Person(25, "John");
und später in Ihrem Code verwenden Sie die folgende Anweisung, um das Objekt zu drucken:
System.out.println(person.toString());
Sie erhalten eine Ausgabe ähnlich der folgenden:
Person@7ab89d
Dies ist das Ergebnis der Implementierung der toString()
Methode, die in der Object
Klasse, einer Superklasse von Person
. Die Dokumentation von Object.toString()
besagt:
Die toString-Methode für die Klasse Object gibt eine Zeichenfolge zurück, die aus dem Namen der Klasse, deren Objekt das Objekt ist, dem Zeichen @, und der vorzeichenlosen hexadezimalen Darstellung des Hashcodes des Objekts besteht. Mit anderen Worten, diese Methode gibt einen String zurück, der dem Wert von entspricht:
getClass().getName() + '@' + Integer.toHexString(hashCode())
Für eine sinnvolle Ausgabe müssen Sie daher die toString()
-Methode überschreiben :
@Override
public String toString() {
return "My name is " + this.name + " and my age is " + this.age;
}
Jetzt wird die Ausgabe sein:
My name is John and my age is 25
Du kannst auch schreiben
System.out.println(person);
Tatsächlich ruft println()
die toString
Methode implizit für das Objekt auf.
Saiten teilen
Sie können einen String
für ein bestimmtes Begrenzungszeichen oder einen regulären Ausdruck String.split()
Sie können die String.split()
-Methode verwenden, die die folgende Signatur aufweist:
public String[] split(String regex)
Beachten Sie, dass Begrenzungszeichen oder reguläre Ausdrücke aus dem resultierenden String-Array entfernt werden.
Beispiel mit Begrenzungszeichen:
String lineFromCsvFile = "Mickey;Bolton;12345;121216";
String[] dataCells = lineFromCsvFile.split(";");
// Result is dataCells = { "Mickey", "Bolton", "12345", "121216"};
Beispiel mit regulärem Ausdruck:
String lineFromInput = "What do you need from me?";
String[] words = lineFromInput.split("\\s+"); // one or more space chars
// Result is words = {"What", "do", "you", "need", "from", "me?"};
Sie können sogar ein String
Literal direkt aufteilen:
String[] firstNames = "Mickey, Frank, Alicia, Tom".split(", ");
// Result is firstNames = {"Mickey", "Frank", "Alicia", "Tom"};
Warnung : Vergessen Sie nicht, dass der Parameter immer als regulärer Ausdruck behandelt wird.
"aaa.bbb".split("."); // This returns an empty array
Im vorigen Beispiel .
wird als Platzhalter für reguläre Ausdrücke behandelt, der mit einem beliebigen Zeichen übereinstimmt. Da jedes Zeichen ein Trennzeichen ist, ist das Ergebnis ein leeres Array.
Aufteilung basierend auf einem Trennzeichen, das ein Regex-Meta-Zeichen ist
Die folgenden Zeichen werden in Regex als Sonderzeichen (auch als Metazeichen bezeichnet) bezeichnet
< > - = ! ( ) [ ] { } \ ^ $ | ? * + .
Um eine Zeichenfolge basierend auf einem der oben genannten Trennzeichen zu Pattern.quote()
, müssen Sie sie entweder mit \\
escape oder mit Pattern.quote()
:
Pattern.quote()
:String s = "a|b|c"; String regex = Pattern.quote("|"); String[] arr = s.split(regex);
Die Sonderzeichen umgehen:
String s = "a|b|c"; String[] arr = s.split("\\|");
Split entfernt leere Werte
split(delimiter)
entfernt standardmäßig leere Zeichenfolgen aus dem Ergebnis-Array. Um diesen Mechanismus zu deaktivieren, müssen Sie eine überladene Version von split(delimiter, limit)
wobei der Grenzwert auf einen negativen Wert gesetzt ist, wie
String[] split = data.split("\\|", -1);
split(regex)
intern das Ergebnis der split(regex, 0)
.
Der Parameter limit steuert, wie oft das Muster angewendet wird, und wirkt sich daher auf die Länge des resultierenden Arrays aus.
Wenn die Grenze n größer als Null ist, wird das Muster höchstens n - 1 mal angewendet, die Länge des Arrays ist nicht größer als n , und der letzte Eintrag des Arrays enthält alle Eingaben, die über den letzten übereinstimmenden Begrenzer liegen.
Wenn n negativ ist, wird das Muster so oft wie möglich angewendet und das Array kann eine beliebige Länge haben.
Wenn n gleich Null ist, wird das Muster so oft wie möglich angewendet, das Array kann beliebig lang sein und nachfolgende leere Zeichenfolgen werden verworfen.
StringTokenizer
mit einem StringTokenizer
Neben der split()
Methode können Strings auch mit einem StringTokenizer
.
StringTokenizer
ist noch restriktiver als String.split()
und auch etwas schwieriger zu verwenden. Es ist im Wesentlichen für das Herausziehen von Token gedacht, die durch einen festen Zeichensatz (als String
) begrenzt sind. Jedes Zeichen dient als Trennzeichen. Aufgrund dieser Einschränkung ist es etwa doppelt so schnell wie String.split()
.
Der standardmäßige Zeichensatz ist ein Leerzeichen ( \t\n\r\f
). Das folgende Beispiel wird jedes Wort separat ausdrucken.
String str = "the lazy fox jumped over the brown fence";
StringTokenizer tokenizer = new StringTokenizer(str);
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
Dies wird ausgedruckt:
the
lazy
fox
jumped
over
the
brown
fence
Sie können verschiedene Zeichensätze zur Trennung verwenden.
String str = "jumped over";
// In this case character `u` and `e` will be used as delimiters
StringTokenizer tokenizer = new StringTokenizer(str, "ue");
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
Dies wird ausgedruckt:
j
mp
d ov
r
Strings mit einem Trennzeichen verbinden
Ein String-Array kann mit der statischen Methode String.join()
:
String[] elements = { "foo", "bar", "foobar" };
String singleString = String.join(" + ", elements);
System.out.println(singleString); // Prints "foo + bar + foobar"
Ebenso gibt es eine überladene String.join()
-Methode für Iterable
s.
Um eine genaue Kontrolle über das Verbinden zu erhalten, können Sie die Klasse StringJoiner verwenden :
StringJoiner sj = new StringJoiner(", ", "[", "]");
// The last two arguments are optional,
// they define prefix and suffix for the result string
sj.add("foo");
sj.add("bar");
sj.add("foobar");
System.out.println(sj); // Prints "[foo, bar, foobar]"
Um einem Stream von Strings beizutreten, können Sie den Verbindungs-Collector verwenden :
Stream<String> stringStream = Stream.of("foo", "bar", "foobar");
String joined = stringStream.collect(Collectors.joining(", "));
System.out.println(joined); // Prints "foo, bar, foobar"
Es gibt auch eine Option, um Präfix und Suffix zu definieren:
Stream<String> stringStream = Stream.of("foo", "bar", "foobar");
String joined = stringStream.collect(Collectors.joining(", ", "{", "}"));
System.out.println(joined); // Prints "{foo, bar, foobar}"
Strings umkehren
Es gibt mehrere Möglichkeiten, wie Sie eine Zeichenfolge umkehren, um sie rückwärts zu machen.
StringBuilder / StringBuffer:
String code = "code"; System.out.println(code); StringBuilder sb = new StringBuilder(code); code = sb.reverse().toString(); System.out.println(code);
Char Array:
String code = "code"; System.out.println(code); char[] array = code.toCharArray(); for (int index = 0, mirroredIndex = array.length - 1; index < mirroredIndex; index++, mirroredIndex--) { char temp = array[index]; array[index] = array[mirroredIndex]; array[mirroredIndex] = temp; } // print reversed System.out.println(new String(array));
Anzahl der Vorkommen eines Teilstrings oder Zeichens in einer Zeichenfolge
countMatches
Methode von org.apache.commons.lang3.StringUtils wird normalerweise verwendet, um die Häufigkeit eines Teilstrings oder eines Zeichens in einem String
:
import org.apache.commons.lang3.StringUtils;
String text = "One fish, two fish, red fish, blue fish";
// count occurrences of a substring
String stringTarget = "fish";
int stringOccurrences = StringUtils.countMatches(text, stringTarget); // 4
// count occurrences of a char
char charTarget = ',';
int charOccurrences = StringUtils.countMatches(text, charTarget); // 3
Andernfalls können Sie für reguläre Java-APIs reguläre Ausdrücke verwenden:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String text = "One fish, two fish, red fish, blue fish";
System.out.println(countStringInString("fish", text)); // prints 4
System.out.println(countStringInString(",", text)); // prints 3
public static int countStringInString(String search, String text) {
Pattern pattern = Pattern.compile(search);
Matcher matcher = pattern.matcher(text);
int stringOccurrences = 0;
while (matcher.find()) {
stringOccurrences++;
}
return stringOccurrences;
}
Stringverkettung und StringBuilders
String-Verkettung kann mit dem Operator +
werden. Zum Beispiel:
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s = s1 + s2 + s3; // abc
Normalerweise führt eine Compilerimplementierung die obige Verkettung mit Methoden durch, die einen StringBuilder
unter der Haube verwenden. Beim Kompilieren würde der Code wie folgt aussehen:
StringBuilder sb = new StringBuilder("a");
String s = sb.append("b").append("c").toString();
StringBuilder
verfügt über mehrere überladene Methoden zum Anhängen verschiedener Typen, z. B. zum Anhängen eines int
anstelle eines String
. Beispielsweise kann eine Implementierung Folgendes konvertieren:
String s1 = "a";
String s2 = "b";
String s = s1 + s2 + 2; // ab2
Zu dem Folgendem:
StringBuilder sb = new StringBuilder("a");
String s = sb.append("b").append(2).toString();
Die obigen Beispiele veranschaulichen eine einfache Verkettung, die effektiv an einer Stelle im Code ausgeführt wird. Die Verkettung umfasst eine einzelne Instanz des StringBuilder
. In einigen Fällen wird eine Verkettung kumulativ durchgeführt, z. B. in einer Schleife:
String result = "";
for(int i = 0; i < array.length; i++) {
result += extractElement(array[i]);
}
return result;
In solchen Fällen wird die Compileroptimierung normalerweise nicht angewendet, und bei jeder Wiederholung wird ein neues StringBuilder
Objekt erstellt. Dies kann optimiert werden, indem der Code explizit in einen einzelnen StringBuilder
:
StringBuilder result = new StringBuilder();
for(int i = 0; i < array.length; i++) {
result.append(extractElement(array[i]));
}
return result.toString();
Ein StringBuilder
wird mit einem Leerzeichen von nur 16 Zeichen initialisiert. Wenn Sie im Voraus wissen, dass Sie größere Zeichenfolgen erstellen, kann es vorteilhaft sein, sie mit ausreichender Größe im Voraus zu initialisieren, damit der interne Puffer nicht in der Größe geändert werden muss:
StringBuilder buf = new StringBuilder(30); // Default is 16 characters
buf.append("0123456789");
buf.append("0123456789"); // Would cause a reallocation of the internal buffer otherwise
String result = buf.toString(); // Produces a 20-chars copy of the string
Wenn Sie viele Strings produzieren, ist es ratsam, StringBuilder
wiederzuverwenden:
StringBuilder buf = new StringBuilder(100);
for (int i = 0; i < 100; i++) {
buf.setLength(0); // Empty buffer
buf.append("This is line ").append(i).append('\n');
outputfile.write(buf.toString());
}
Wenn (und nur wenn) mehrere Threads in denselben Puffer schreiben, verwenden Sie StringBuffer , eine synchronized
Version von StringBuilder
. Da jedoch normalerweise nur ein einzelner Thread in einen Puffer schreibt, ist es normalerweise schneller, StringBuilder
ohne Synchronisation zu verwenden.
Verwenden der concat () -Methode:
String string1 = "Hello ";
String string2 = "world";
String string3 = string1.concat(string2); // "Hello world"
Dies gibt eine neue Zeichenfolge zurück, die string1 ist und am Ende mit string2 versehen wird. Sie können die concat () -Methode auch mit String-Literalen verwenden, wie in:
"My name is ".concat("Buyya");
Teile von Strings ersetzen
Zwei Möglichkeiten zum Ersetzen: durch Regex oder durch exakte Übereinstimmung.
Hinweis: Das ursprüngliche String-Objekt bleibt unverändert, der Rückgabewert enthält den geänderten String.
Genaue Übereinstimmung
Ersetzen Sie ein einzelnes Zeichen durch ein anderes einzelnes Zeichen:
String replace(char oldChar, char newChar)
Gibt eine neue Zeichenfolge zurück, die sich aus dem Ersetzen aller Vorkommen von oldChar in dieser Zeichenfolge durch newChar ergibt.
String s = "popcorn";
System.out.println(s.replace('p','W'));
Ergebnis:
WoWcorn
Ersetzen Sie die Zeichenfolge durch eine andere Zeichenfolge:
String replace(CharSequence target, CharSequence replacement)
Ersetzt jeden Teilstring dieser Zeichenfolge, der der Literal-Zielsequenz entspricht, durch die angegebene Literal-Ersetzungssequenz.
String s = "metal petal et al.";
System.out.println(s.replace("etal","etallica"));
Ergebnis:
metallica petallica et al.
Regex
Hinweis : Die Gruppierung verwendet das Zeichen $
um auf die Gruppen zu verweisen, wie beispielsweise $1
.
Alle Spiele ersetzen:
String replaceAll(String regex, String replacement)
Ersetzt jede Teilzeichenfolge dieser Zeichenfolge, die dem angegebenen regulären Ausdruck entspricht, durch die angegebene Ersetzung.
String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));
Ergebnis:
spiral metallica petallica et al.
Nur das erste Spiel ersetzen:
String replaceFirst(String regex, String replacement)
Ersetzt den ersten Teilstring dieser Zeichenfolge, der dem angegebenen regulären Ausdruck entspricht, durch die angegebene Ersetzung
String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));
Ergebnis:
spiral metallica petal et al.
Entfernen Sie Whitespace vom Anfang und Ende einer Zeichenfolge
Die trim()
-Methode gibt einen neuen String zurück, wobei der führende und der nachfolgende Leerraum entfernt werden.
String s = new String(" Hello World!! ");
String t = s.trim(); // t = "Hello World!!"
Wenn Sie trim
einen String, der keine Leerzeichen hat zu entfernen, müssen Sie die gleiche String - Instanz zurückgegeben werden.
Beachten Sie, dass die trim()
-Methode eine eigene Vorstellung von Whitespace hat , die sich von der von der Character.isWhitespace()
-Methode verwendeten Vorstellung unterscheidet:
Alle ASCII-Steuerzeichen mit den Codes
U+0000
bisU+0020
werden als Leerzeichen betrachtet und mittrim()
. Dies beinhaltetU+0020 'SPACE'
,U+0009 'CHARACTER TABULATION'
,U+000A 'LINE FEED'
undU+000D 'CARRIAGE RETURN'
, aber auch die Zeichen wieU+0007 'BELL'
.Unicode-Whitespace wie
U+00A0 'NO-BREAK SPACE'
oderU+2003 'EM SPACE'
werden vontrim()
nicht erkannt.
String-Pool und Heapspeicher
Wie viele Java-Objekte werden alle String
Instanzen auf dem Heap erstellt, sogar Literale. Wenn die JVM ein String
Literal findet, das keine entsprechende Referenz im Heap hat, erstellt die JVM eine entsprechende String
Instanz auf dem Heap und speichert auch einen Verweis auf die neu erstellte String
Instanz im String-Pool. Alle anderen Verweise auf dasselbe String
Literal werden durch die zuvor erstellte String
Instanz im Heap ersetzt.
Schauen wir uns das folgende Beispiel an:
class Strings
{
public static void main (String[] args)
{
String a = "alpha";
String b = "alpha";
String c = new String("alpha");
//All three strings are equivalent
System.out.println(a.equals(b) && b.equals(c));
//Although only a and b reference the same heap object
System.out.println(a == b);
System.out.println(a != c);
System.out.println(b != c);
}
}
Die Ausgabe des obigen ist:
true
true
true
true
Wenn Sie einen String in doppelte Anführungszeichen setzen, wird zuerst nach String mit demselben Wert im String-Pool gesucht. Wenn er gefunden wird, wird nur der Verweis zurückgegeben. Andernfalls wird ein neuer String im Pool erstellt, und der Verweis wird zurückgegeben.
Mit dem neuen Operator erzwingen wir jedoch die String-Klasse, um ein neues String-Objekt im Heap-Bereich zu erstellen. Wir können die intern () -Methode verwenden, um sie in den Pool einzufügen, oder auf ein anderes String-Objekt aus einem String-Pool mit demselben Wert verweisen.
Der String-Pool selbst wird auch auf dem Heap erstellt.
Vor Java 7 wurden String
Literale im Laufzeitkonstantenpool im Methodenbereich von PermGen
, der eine feste Größe hatte.
Der String-Pool befand sich auch in PermGen
.
In JDK 7 werden internierte Zeichenfolgen nicht mehr bei der permanenten Generierung des Java-Heaps zugewiesen, sondern im Hauptteil des Java-Heaps (als junge und alte Generationen bezeichnet), zusammen mit den anderen von der Anwendung erstellten Objekten . Diese Änderung führt dazu, dass sich mehr Daten im Haupt-Java-Heap und weniger Daten bei der permanenten Generierung befinden. Daher müssen möglicherweise die Heap-Größen angepasst werden. Die meisten Anwendungen werden aufgrund dieser Änderung nur relativ geringe Unterschiede in der Heap-Nutzung
String.intern()
größeren Anwendungen, die viele Klassen laden oder dieString.intern()
-MethodeString.intern()
verwenden, werden jedoch größere Unterschiede auftreten.
Groß- und Kleinschreibung
switch
selbst kann nicht so konfiguriert werden, dass er nicht zwischen Groß- und Kleinschreibung unterscheidet. Wenn er jedoch unbedingt erforderlich ist, kann er sich mit toLowerCase()
oder toUpperCase
unempfindlich gegenüber der Eingabezeichenfolge toUpperCase
:
switch (myString.toLowerCase()) {
case "case1" :
...
break;
case "case2" :
...
break;
}
In acht nehmen
-
Locale
kann beeinflussen, wie sich die Fälle ändern. - Es muss darauf geachtet werden, dass in den Beschriftungen keine Großbuchstaben enthalten sind - diese werden niemals ausgeführt!