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.

Java SE 7

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.

Java SE 7

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.
}

Live-Demo

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.
}

Live-Demo

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

Live-Demo


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

Java SE 7

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;
}

Live-Demo

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.

Java SE 7

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 von String.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:

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:

  1. Deklarieren Sie einen String.
  2. Geben Sie die Zeichenfolge ein.
  3. Konvertieren Sie die Zeichenfolge in ein Zeichenfeld.
  4. Geben Sie das Zeichen ein, nach dem gesucht werden soll.
  5. Suchen Sie nach dem Zeichen im Zeichenfeld.
  6. 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.
  7. Ändern Sie das ursprüngliche Zeichen aus dem Zeichen-Array.
  8. 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

Live Demo auf Ideone


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

Live Demo auf Ideone

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

Live Demo auf Ideone

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

Live Demo auf Ideone

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.

Java SE 7

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.

Java SE 7

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")
Java SE 7

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());

Live Demo auf Ideone

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);

Live Demo auf Ideone

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

Java SE 8

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.

  1. StringBuilder / StringBuffer:

     String code = "code";
     System.out.println(code);
    
     StringBuilder sb = new StringBuilder(code); 
     code = sb.reverse().toString();
    
     System.out.println(code);
    
  2. 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 bis U+0020 werden als Leerzeichen betrachtet und mit trim() . Dies beinhaltet U+0020 'SPACE' , U+0009 'CHARACTER TABULATION' , U+000A 'LINE FEED' und U+000D 'CARRIAGE RETURN' , aber auch die Zeichen wie U+0007 'BELL' .

  • Unicode-Whitespace wie U+00A0 'NO-BREAK SPACE' oder U+2003 'EM SPACE' werden von trim() 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

Diagramm des Java-Heap- und String-Pools 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.

Java SE 7

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 .

Java SE 7

RFC: 6962931

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 die String.intern() -Methode String.intern() verwenden, werden jedoch größere Unterschiede auftreten.

Groß- und Kleinschreibung

Java SE 7

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!


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow