Zoeken…


Invoering

Tekenreeksen ( java.lang.String ) zijn stukjes tekst die in uw programma zijn opgeslagen. Strings zijn geen primitief gegevenstype in Java , maar ze komen veel voor in Java-programma's.

In Java zijn strings onveranderlijk, wat betekent dat ze niet kunnen worden gewijzigd. (Klik hier voor een meer grondige verklaring van onveranderlijkheid.)

Opmerkingen

Omdat Java-tekenreeksen onveranderlijk zijn , retourneren alle methoden die een String manipuleren een nieuw String object . Ze veranderen de originele String . Dit omvat substring- en vervangingsmethoden die C- en C ++ -programmeurs zouden verwachten het doel String object te muteren.


Gebruik een StringBuilder plaats van String als u meer dan twee String objecten wilt samenvoegen waarvan de waarden niet kunnen worden bepaald tijdens het compileren. Deze techniek is performanter dan het maken van nieuwe String objecten en deze samenvoegen omdat StringBuilder is.

StringBuffer kan ook worden gebruikt om String objecten samen te voegen. Deze klasse is echter minder performant omdat deze is ontworpen om draadveilig te zijn en vóór elke bewerking een mutex verkrijgt. Omdat je bijna nooit thread-safety nodig hebt wanneer je strings samenvoegt, is het het beste om StringBuilder te gebruiken.

Als u een tekenreeksen als een enkele uitdrukking kunt uitdrukken, is het beter om de operator + gebruiken. De Java-compiler converteert een expressie met + aaneenschakelingen naar een efficiënte reeks bewerkingen met String.concat(...) of StringBuilder . Het advies om StringBuilder te gebruiken is expliciet alleen van toepassing wanneer de aaneenschakeling meerdere uitdrukkingen omvat.


Sla geen gevoelige informatie op in strings. Als iemand een geheugendump van uw actieve toepassing kan verkrijgen, kan deze alle bestaande String objecten vinden en de inhoud ervan lezen. Dit omvat String objecten die onbereikbaar zijn en in afwachting zijn van afvalinzameling. Als dit een probleem is, moet u gevoelige tekenreeksgegevens wissen zodra u klaar bent. U kunt dit niet doen met String objecten omdat deze onveranderlijk zijn. Het is daarom raadzaam om char[] -objecten te gebruiken om gevoelige tekengegevens te bevatten en deze te wissen (bijv. Overschrijven met '\000' tekens) wanneer u klaar bent.


Alle String worden op de heap gemaakt, zelfs instanties die overeenkomen met tekenreeksliteralen. Het bijzondere van stringliterals is dat de JVM ervoor zorgt dat alle literals die gelijk zijn (dat wil zeggen die uit dezelfde tekens bestaat) worden weergegeven door een enkel String object (dit gedrag wordt gespecificeerd in JLS). Dit wordt geïmplementeerd door JVM-klasse-laders. Wanneer een klassenlader een klasse laadt, scant deze op stringliterals die in de klassedefinitie worden gebruikt. Telkens wanneer hij er een ziet, wordt gecontroleerd of er al een record in de stringpool staat voor dit letterlijke (met het letterlijke als sleutel) . Als er al een vermelding voor het letterlijke is, wordt de verwijzing naar een String instantie gebruikt die is opgeslagen als het paar voor dat letterlijke. Anders wordt een nieuwe String instantie gemaakt en wordt een verwijzing naar de instantie opgeslagen voor de letterlijke (gebruikt als sleutel) in de stringpool. (Zie ook string-interning ).

De string pool wordt gehouden in de Java-heap en is onderworpen aan de normale inzameling van afval.

Java SE 7

In releases van Java vóór Java 7, werd de string pool gehouden in een speciaal deel van de heap bekend als "PermGen". Dit deel werd slechts incidenteel verzameld.

Java SE 7

In Java 7 is de stringpool verwijderd van "PermGen".

Merk op dat stringliteralen impliciet bereikbaar zijn vanaf elke methode die ze gebruikt. Dit betekent dat de bijbehorende String objecten alleen als afval kunnen worden verzameld als de code zelf afval is.


Tot Java 8 worden String objecten geïmplementeerd als een UTF-16 char-array (2 bytes per char). Er is een voorstel in Java 9 om String te implementeren als een bytearray met een codeervlagveld om op te merken of de string is gecodeerd als bytes (LATIN-1) of tekens (UTF-16).

Strings vergelijken

Als u Strings voor gelijkheid wilt vergelijken, moet u de methoden equals of equalsIgnoreCase het String-object gebruiken.

Het volgende fragment bepaalt bijvoorbeeld of de twee instanties van String op alle tekens gelijk zijn:

String firstString = "Test123";
String secondString = "Test" + 123;

if (firstString.equals(secondString)) {
   // Both Strings have the same content.
}

Live demonstratie

In dit voorbeeld worden ze vergeleken, ongeacht hun case:

String firstString = "Test123";
String secondString = "TEST123";

if (firstString.equalsIgnoreCase(secondString)) {
    // Both Strings are equal, ignoring the case of the individual characters.
}

Live demonstratie

Houd er rekening mee dat equalsIgnoreCase u geen Locale kunt opgeven. Als u bijvoorbeeld de twee woorden "Taki" en "TAKI" in het Engels vergelijkt, zijn ze gelijk; in het Turks zijn ze echter anders (in het Turks is de kleine letter I ı ). Voor dit soort gevallen is het de oplossing om beide reeksen te converteren naar kleine letters (of hoofdletters) met Locale en vervolgens te vergelijken met equals .

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 demonstratie


Gebruik de operator == niet om strings te vergelijken

Tenzij u kunt garanderen dat alle tekenreeksen zijn geïnterneerd (zie hieronder), moet u de operatoren == of != gebruiken om tekenreeksen te vergelijken. Deze operatoren testen feitelijk referenties, en aangezien meerdere String objecten dezelfde String kunnen vertegenwoordigen, kan dit een verkeerd antwoord geven.

Gebruik in plaats daarvan de methode String.equals(Object) , waarmee de String-objecten worden vergeleken op basis van hun waarden. Raadpleeg Pitfall: met behulp van == om strings te vergelijken voor een gedetailleerde uitleg.


Strings vergelijken in een schakelinstructie

Java SE 7

Vanaf Java 1.7 is het mogelijk om een String-variabele met literals te vergelijken in een switch instructie. Zorg ervoor dat de String niet nul is, anders zal deze altijd een NullPointerException gooien. Waarden worden vergeleken met String.equals , dat wil zeggen hoofdlettergevoelig.

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 demonstratie

Strings vergelijken met constante waarden

Wanneer u een String met een constante waarde vergelijkt, kunt u de constante waarde aan de linkerkant van equals om ervoor te zorgen dat u geen NullPointerException als de andere tekenreeks null .

"baz".equals(foo)

Terwijl foo.equals("baz") een NullPointerException zal NullPointerException als foo null , zal "baz".equals(foo) als false evalueren.

Java SE 7

Een beter leesbaar alternatief is het gebruik van Objects.equals() , die een Objects.equals(foo, "baz") op beide parameters: Objects.equals(foo, "baz") .

( Opmerking: het valt te NullPointerExceptions of het beter is om NullPointerExceptions in het algemeen te vermijden, of ze te laten gebeuren en vervolgens de grondoorzaak op te lossen; zie hier en hier . Het is zeker niet gerechtvaardigd om de vermijdingsstrategie "beste praktijk" te noemen.)

String bestellingen

De klasse String implementeert Comparable<String> met de methode String.compareTo (zoals beschreven aan het begin van dit voorbeeld). Dit maakt de natuurlijke volgorde van String objecten hoofdlettergevoelig. De klasse String biedt een Comparator<String> CASE_INSENSITIVE_ORDER naam CASE_INSENSITIVE_ORDER geschikt is voor niet-hoofdlettergevoelig sorteren.

In vergelijking met geïnterneerde strings

De Java Language Specification ( JLS 3.10.6 ) vermeldt het volgende:

"Bovendien verwijst een letterlijke tekenreeks altijd naar dezelfde instantie van klasse String . Dit komt omdat tekenreeksliteralen - of, meer in het algemeen, strings die de waarden zijn van constante expressies - worden geïnterneerd om unieke instanties te delen, met behulp van de methode String.intern . "

Dit betekent dat het veilig is om verwijzingen naar twee letterlijke tekenreeksen te vergelijken met behulp van == . Hetzelfde geldt bovendien voor verwijzingen naar String objecten die zijn geproduceerd met de methode String.intern() .

Bijvoorbeeld:

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

Achter de schermen houdt het interning-mechanisme een hashtabel bij die alle geïnterneerde tekenreeksen bevat die nog steeds bereikbaar zijn . Wanneer u intern() oproept in een String , zoekt de methode het object op in de hashtabel:

  • Als de tekenreeks wordt gevonden, wordt die waarde geretourneerd als de geïnterneerde tekenreeks.
  • Anders wordt een kopie van de tekenreeks toegevoegd aan de hashtabel en wordt die tekenreeks geretourneerd als de geïnterneerde tekenreeks.

Het is mogelijk om interning te gebruiken om strings te vergelijken met == . Er zijn echter aanzienlijke problemen hiermee; zie Valkuil - Interne tekenreeksen zodat u == kunt gebruiken, is een slecht idee voor meer informatie. Het wordt in de meeste gevallen niet aanbevolen.

Het hoofdlettergebruik van tekens binnen een tekenreeks wijzigen

Het type String biedt twee methoden voor het converteren van tekenreeksen tussen hoofdletters en kleine letters:

  • toUpperCase om alle tekens naar hoofdletters te converteren
  • toLowerCase om alle tekens naar kleine letters te converteren

Beide methoden retourneren de geconverteerde strings als nieuwe String instanties: de oorspronkelijke String objecten worden niet gewijzigd omdat String onveranderlijk is in Java. Zie dit voor meer informatie over onveranderlijkheid: onveranderlijkheid van tekenreeksen 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"

Niet-alfabetische tekens, zoals cijfers en leestekens, worden niet beïnvloed door deze methoden. Merk op dat deze methoden onder bepaalde omstandigheden mogelijk ook onjuist omgaan met bepaalde Unicode-tekens.


Opmerking : deze methoden zijn locale-gevoelig en kunnen onverwachte resultaten opleveren als ze worden gebruikt op strings die bedoeld zijn om onafhankelijk van de locale te worden geïnterpreteerd. Voorbeelden zijn programmeertaal-ID's, protocolsleutels en HTML tags.

Bijvoorbeeld: "TITLE".toLowerCase() in een Turkse landinstelling geeft " tıtle " terug, waarbij ı (\u0131) het LATIN SMALL LETTER DOTLESS I- teken is. Om juiste resultaten te verkrijgen voor locale ongevoelige tekenreeksen, geeft u Locale.ROOT als parameter door aan de overeenkomstige methode voor het converteren van hoofdletters (bijvoorbeeld toLowerCase(Locale.ROOT) of toUpperCase(Locale.ROOT) ).

Hoewel het gebruik van Locale.ENGLISH ook in de meeste gevallen correct is, is de taal invariante manier Locale.ROOT .

Een gedetailleerde lijst met Unicode-tekens die een speciale behuizing vereisen, is te vinden op de website van Unicode Consortium .

Hoofdlettergebruik van een specifiek teken binnen een ASCII-reeks:

Om het geval van een specifiek karakter van een ASCII-reeks te wijzigen, kan het volgende algoritme worden gebruikt:

Stappen:

  1. Declareer een string.
  2. Voer de string in.
  3. Converteer de tekenreeks naar een tekenreeks.
  4. Voer het teken in dat moet worden doorzocht.
  5. Zoek naar het karakter in de character array.
  6. Controleer indien gevonden of het teken kleine letters of hoofdletters is.
    • Voeg in hoofdletters 32 toe aan de ASCII-code van het teken.
    • Als kleine letters, 32 aftrekken van de ASCII-code van het teken.
  7. Verander het originele karakter uit de Character array.
  8. Converteer de character array terug naar de string.

Voila, de zaak van het personage is veranderd.

Een voorbeeld van de code voor het algoritme is:

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

Een string zoeken binnen een andere string

Om te controleren of een bepaalde String a in een String b of niet, kunnen we de methode String.contains() met de volgende syntaxis:

b.contains(a); // Return true if a is contained in b, false otherwise

De methode String.contains() kan worden gebruikt om te controleren of er een CharSequence in de String kan worden gevonden. De methode zoekt hoofdlettergevoelig naar de tekenreeks a in de tekenreeks 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 op Ideone


Gebruik String.indexOf() om de exacte positie te vinden waar een string in een andere string begint:

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 op Ideone

De methode String.indexOf() retourneert de eerste index van een char of String in een andere String . De methode retourneert -1 als deze niet wordt gevonden.

Opmerking : de methode String.indexOf() is hoofdlettergevoelig.

Voorbeeld van zoeken waarbij de casus wordt genegeerd:

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 op Ideone

De lengte van een string verkrijgen

Om de lengte van een String object te krijgen, roept u de methode length() aan. De lengte is gelijk aan het aantal UTF-16 code-eenheden (tekens) in de string.

String str = "Hello, World!";
System.out.println(str.length()); // Prints out 13

Live demo op Ideone

Een char in een tekenreeks is UTF-16-waarde. Unicode-codepunten waarvan de waarden ≥ 0x1000 zijn (bijvoorbeeld de meeste emoji's) gebruiken twee char-posities. Om het aantal Unicode-code punten in een string, tel ongeacht of elk codepoint past in een UTF-16 char value, kunt u het gebruik codePointCount methode:

int length = str.codePointCount(0, str.length());

Je kunt ook een stroom codepunten gebruiken, vanaf Java 8:

int length = str.codePoints().count();

subtekenreeksen

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

Substrings kunnen ook worden toegepast om tekens in de oorspronkelijke tekenreeks te knippen en toe te voegen / te vervangen. U stond bijvoorbeeld voor een Chinese datum die Chinese tekens bevat, maar u wilt deze opslaan als een goed opgemaakte datumreeks.

String datestring = "2015年11月17日"
datestring = datestring.substring(0, 4) + "-" + datestring.substring(5,7) + "-" + datestring.substring(8,10);
//Result will be 2015-11-17

De substring- methode extraheert een stuk van een String . Wanneer één parameter wordt opgegeven, is de parameter het begin en loopt het stuk door tot het einde van de String . Wanneer twee parameters worden gegeven, is de eerste parameter het startteken en de tweede parameter is de index van het teken direct na het einde (het teken bij de index is niet inbegrepen). Een gemakkelijke manier om te controleren is dat de aftrekking van de eerste parameter van de tweede de verwachte lengte van de tekenreeks zou moeten opleveren.

Java SE 7

In JDK <7u6-versies instantieert de substring methode een String dezelfde achtergrondtekens char[] als de oorspronkelijke String en heeft de interne offset en count ingesteld op het begin en de lengte van het resultaat. Dergelijk delen kan geheugenlekken veroorzaken, wat kan worden voorkomen door new String(s.substring(...)) aan te roepen om het maken van een kopie te forceren, waarna het char[] vuilnis kan worden verzameld.

Java SE 7

Van JDK 7u6 kopieert de substring methode altijd de gehele onderliggende char[] array, waardoor de complexiteit lineair is in vergelijking met de vorige constante, maar tegelijkertijd de afwezigheid van geheugenlekken wordt gegarandeerd.

Het negende karakter in een string krijgen

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"

Om het n-de karakter in een string te krijgen, roept u eenvoudig charAt(n) op een String , waarbij n de index is van het karakter dat u wilt ophalen

OPMERKING: index n begint bij 0 , dus het eerste element is bij n = 0.

Platform onafhankelijke nieuwe lijnscheider

Aangezien het nieuwe lijnscheidingsteken van platform tot platform varieert (bijvoorbeeld \n op Unix-achtige systemen of \r\n op Windows), is het vaak noodzakelijk om een platformonafhankelijke manier te hebben om er toegang toe te krijgen. In Java kan het worden opgehaald uit een systeemeigenschap:

System.getProperty("line.separator")
Java SE 7

Omdat het nieuwe scheidingsteken zo vaak nodig is, is vanuit Java 7 een sneltoetsmethode beschikbaar die exact hetzelfde resultaat oplevert als de bovenstaande code:

System.lineSeparator()

Opmerking : Aangezien het zeer onwaarschijnlijk is dat het nieuwe scheidingsteken tijdens de uitvoering van het programma verandert, is het een goed idee om het op te slaan in een statische laatste variabele in plaats van het elke keer op te halen uit de systeemeigenschap.

Wanneer u String.format , gebruikt u %n plaats van \n of '\ r \ n' om een platformonafhankelijke nieuwe lijnscheider uit te voeren.

System.out.println(String.format('line 1: %s.%nline 2: %s%n', lines[0],lines[1]));

Methode toString () toevoegen voor aangepaste objecten

Stel dat u de volgende Person hebt gedefinieerd:

public class Person {

    String name;
    int age;
    
    public Person (int age, String name) {
        this.age = age;
        this.name = name;
    }
}

Als u een nieuw Person object instantieert:

Person person = new Person(25, "John");

en later in uw code gebruikt u de volgende instructie om het object af te drukken:

System.out.println(person.toString());

Live demo op Ideone

u krijgt een uitvoer vergelijkbaar met het volgende:

Person@7ab89d

Dit is het resultaat van de implementatie van de methode toString() die is gedefinieerd in de klasse Object , een superklasse van Person . De documentatie van Object.toString() vermeldt:

De methode toString voor klasse Object retourneert een tekenreeks die bestaat uit de naam van de klasse waarvan het object een instantie is, het apenstaartje '@' en de niet-ondertekende hexadecimale weergave van de hash-code van het object. Met andere woorden, deze methode retourneert een tekenreeks die gelijk is aan de waarde van:

getClass().getName() + '@' + Integer.toHexString(hashCode())

Voor een zinvolle uitvoer moet u de methode toString() overschrijven :

@Override
public String toString() {
    return "My name is " + this.name + " and my age is " + this.age;
}

Nu zal de output zijn:

My name is John and my age is 25

Je kunt ook schrijven

System.out.println(person);

Live demo op Ideone

In feite roept println() impliciet de toString methode op het object aan.

Snaren splitsen

U kunt een String splitsen op een bepaald scheidingsteken of een reguliere expressie , u kunt de String.split() gebruiken met de volgende handtekening:

public String[] split(String regex)

Merk op dat het afbakenen van karakter of reguliere expressie wordt verwijderd uit de resulterende String Array.

Voorbeeld met een scheidingsteken:

String lineFromCsvFile = "Mickey;Bolton;12345;121216";
String[] dataCells = lineFromCsvFile.split(";");
// Result is dataCells = { "Mickey", "Bolton", "12345", "121216"};

Voorbeeld met reguliere expressie:

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

Je kunt zelfs een letterlijke String direct splitsen:

String[] firstNames = "Mickey, Frank, Alicia, Tom".split(", ");
// Result is firstNames = {"Mickey", "Frank", "Alicia", "Tom"};

Waarschuwing : vergeet niet dat de parameter altijd wordt behandeld als een reguliere expressie.

"aaa.bbb".split("."); // This returns an empty array

In het vorige voorbeeld . wordt behandeld als het reguliere expressie-jokerteken dat overeenkomt met elk teken, en omdat elk teken een scheidingsteken is, is het resultaat een lege array.


Splitsen op basis van een scheidingsteken dat een regex-metakarakter is

De volgende tekens worden als speciaal beschouwd (ook wel meta-tekens genoemd) in regex

  < > - = ! ( ) [ ] { } \ ^ $ | ? * + . 

Als u een tekenreeks wilt splitsen op basis van een van de bovenstaande scheidingstekens, moet u ze laten ontsnappen met \\ of Pattern.quote() :

  • Pattern.quote() :

     String s = "a|b|c";
     String regex = Pattern.quote("|");
     String[] arr = s.split(regex);
    
  • Ontsnappen aan de speciale tekens:

     String s = "a|b|c";
     String[] arr = s.split("\\|");
    

Splitsen verwijdert lege waarden

split(delimiter) verwijdert standaard achterblijvende lege strings uit de resultatenmatrix. Om dit mechanisme uit te schakelen, moeten we de overbelaste versie van split(delimiter, limit) met limiet ingesteld op negatieve waarde zoals

String[] split = data.split("\\|", -1);

split(regex) retourneert intern het resultaat van split(regex, 0) .

De parameter limit bepaalt het aantal keren dat het patroon wordt toegepast en beïnvloedt daarom de lengte van de resulterende array.
Als de limiet n groter is dan nul, wordt het patroon maximaal n - 1 keer toegepast, is de lengte van de array niet groter dan n en bevat de laatste invoer van de array alle invoer voorbij het laatst overeenkomende scheidingsteken.
Als n negatief is, wordt het patroon zo vaak mogelijk toegepast en kan de array elke lengte hebben.
Als n nul is, wordt het patroon zo vaak mogelijk toegepast, kan de array elke lengte hebben en worden lege reeksen weggegooid.


Splitsen met een StringTokenizer

Naast de methode split() kunnen strings ook worden gesplitst met een StringTokenizer .

StringTokenizer is nog beperkter dan String.split() , en ook een beetje moeilijker te gebruiken. Het is in wezen ontworpen voor het uittrekken van tokens gescheiden door een vaste reeks tekens (gegeven als een String ). Elk karakter fungeert als scheidingsteken. Vanwege deze beperking is het ongeveer twee keer zo snel als String.split() .

Standaard tekenset zijn lege spaties ( \t\n\r\f ). In het volgende voorbeeld wordt elk woord afzonderlijk afgedrukt.

String str = "the lazy fox jumped over the brown fence";
StringTokenizer tokenizer = new StringTokenizer(str);
while (tokenizer.hasMoreTokens()) {
    System.out.println(tokenizer.nextToken());
}

Dit wordt afgedrukt:

the
lazy 
fox 
jumped 
over 
the 
brown 
fence

U kunt verschillende tekensets gebruiken voor scheiding.

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

Dit wordt afgedrukt:

j
mp 
d ov
r

Verbinden van strings met een scheidingsteken

Java SE 8

Een reeks strings kan worden samengevoegd met de statische methode String.join() :

String[] elements = { "foo", "bar", "foobar" };
String singleString = String.join(" + ", elements);

System.out.println(singleString); // Prints "foo + bar + foobar"     

Evenzo is er een overbelaste String.join() -methode voor Iterable s.


Voor een fijnmazige controle over het lid worden, kunt u de StringJoiner- klasse gebruiken:

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]"

Om deel te nemen aan een reeks strings, kunt u de samenvoegende verzamelaar gebruiken :

Stream<String> stringStream = Stream.of("foo", "bar", "foobar");
String joined = stringStream.collect(Collectors.joining(", "));
System.out.println(joined); // Prints "foo, bar, foobar"

Er is hier ook een optie om het voor- en achtervoegsel te definiëren:

Stream<String> stringStream = Stream.of("foo", "bar", "foobar");
String joined = stringStream.collect(Collectors.joining(", ", "{", "}"));
System.out.println(joined); // Prints "{foo, bar, foobar}"

Omkerende snaren

Er zijn een paar manieren om een string om te keren om deze achteruit te laten gaan.

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

Tellingen van een substring of karakter in een string tellen

countMatches methode van org.apache.commons.lang3.StringUtils wordt meestal gebruikt om exemplaren van een substring of teken in een String te tellen:

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

Anders voor doet hetzelfde met standaard Java API's die u met reguliere expressies zou kunnen gebruiken:

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

String-aaneenschakeling en StringBuilders

String-aaneenschakeling kan worden uitgevoerd met de operator + . Bijvoorbeeld:

String s1 = "a";
String s2 = "b";
String s3 = "c";
String s = s1 + s2 + s3; // abc

Normaal gesproken zal een compiler-implementatie de bovenstaande aaneenschakeling uitvoeren met behulp van methoden waarbij een StringBuilder onder de motorkap betrokken is. Wanneer gecompileerd, lijkt de code op de onderstaande:

StringBuilder sb = new StringBuilder("a");
String s = sb.append("b").append("c").toString();

StringBuilder heeft verschillende overbelaste methoden voor het toevoegen van verschillende typen, bijvoorbeeld om een int toe te voegen in plaats van een String . Een implementatie kan bijvoorbeeld het volgende converteren:

String s1 = "a";
String s2 = "b";    
String s = s1 + s2 + 2; // ab2

Naar het volgende:

StringBuilder sb = new StringBuilder("a");
String s = sb.append("b").append(2).toString();

De bovenstaande voorbeelden illustreren een eenvoudige aaneenschakeling die effectief op één plaats in de code wordt uitgevoerd. De aaneenschakeling betreft een enkel exemplaar van de StringBuilder . In sommige gevallen wordt een aaneenschakeling uitgevoerd op een cumulatieve manier zoals in een lus:

String result = "";
for(int i = 0; i < array.length; i++) {
    result += extractElement(array[i]);
}
return result;

In dergelijke gevallen wordt de compileroptimalisatie meestal niet toegepast en maakt elke iteratie een nieuw StringBuilder object. Dit kan worden geoptimaliseerd door de code expliciet te transformeren om een enkele StringBuilder :

StringBuilder result = new StringBuilder();
for(int i = 0; i < array.length; i++) {
    result.append(extractElement(array[i]));
}
return result.toString();

Een StringBuilder wordt geïnitialiseerd met een lege ruimte van slechts 16 tekens. Als u van tevoren weet dat u grotere tekenreeksen gaat bouwen, kan het nuttig zijn om dit van tevoren met voldoende grootte te initialiseren, zodat het formaat van de interne buffer niet hoeft te worden gewijzigd:

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

Als u veel tekenreeksen produceert, is het raadzaam StringBuilder s opnieuw te gebruiken:

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

Als (en alleen als) meerdere threads naar dezelfde buffer schrijven, gebruikt u StringBuffer , een synchronized versie van StringBuilder . Maar omdat meestal slechts één thread naar een buffer schrijft, is het meestal sneller om StringBuilder zonder synchronisatie te gebruiken.

Met behulp van de methode concat ():

String string1 = "Hello ";
String string2 = "world";
String string3 = string1.concat(string2);  // "Hello world"

Dit retourneert een nieuwe string die string1 is waaraan aan het einde string2 is toegevoegd. U kunt de methode concat () ook gebruiken met tekenreeksliteralen, zoals in:

"My name is ".concat("Buyya");

Delen van strings vervangen

Twee manieren om te vervangen: door regex of door exact zoeken.

Opmerking: het oorspronkelijke String-object blijft ongewijzigd, de retourwaarde bevat de gewijzigde String.

Exacte overeenkomst

Vervang een enkel karakter door een ander enkel karakter:

String replace(char oldChar, char newChar) 

Retourneert een nieuwe tekenreeks die resulteert uit het vervangen van alle exemplaren van oldChar in deze tekenreeks door newChar.

String s = "popcorn";
System.out.println(s.replace('p','W'));

Resultaat:

WoWcorn

Reeks tekens vervangen door een andere reeks tekens:

String replace(CharSequence target, CharSequence replacement) 

Vervangt elke substring van deze tekenreeks die overeenkomt met de letterlijke doelreeks door de opgegeven letterlijke vervangingsreeks.

String s = "metal petal et al.";
System.out.println(s.replace("etal","etallica"));

Resultaat:

metallica petallica et al.

regex

Opmerking : de groepering gebruikt het $ -teken om naar de groepen te verwijzen, zoals $1 .

Vervang alle overeenkomsten:

String replaceAll(String regex, String replacement) 

Vervangt elke substring van deze tekenreeks die overeenkomt met de gegeven reguliere expressie door de gegeven vervanging.

String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));

Resultaat:

spiral metallica petallica et al.

Alleen eerste wedstrijd vervangen:

String replaceFirst(String regex, String replacement) 

Vervangt de eerste substring van deze tekenreeks die overeenkomt met de gegeven reguliere expressie door de gegeven vervanging

String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));

Resultaat:

spiral metallica petal et al.

Verwijder witruimte vanaf het begin en einde van een string

De methode trim() retourneert een nieuwe tekenreeks met de voorloop- en volgspaties verwijderd.

String s = new String("   Hello World!!  ");
String t = s.trim();  // t = "Hello World!!"

Als u een String trim die geen witruimte heeft om te verwijderen, krijgt u dezelfde String-instantie terug.

Merk op dat de methode trim() een eigen notie van witruimte heeft , die verschilt van de notie die wordt gebruikt door de methode Character.isWhitespace() :

  • Alle ASCII-besturingstekens met codes U+0000 tot U+0020 worden als witruimte beschouwd en worden verwijderd door trim() . Dit omvat U+0020 'SPACE' , U+0009 'CHARACTER TABULATION' , U+000A 'LINE FEED' en U+000D 'CARRIAGE RETURN' karakters, maar ook de karakters zoals U+0007 'BELL' .

  • Unicode witruimte zoals U+00A0 'NO-BREAK SPACE' of U+2003 'EM SPACE' worden niet herkend door trim() .

String pool en heap opslag

Zoals veel Java-objecten, worden alle String instanties op de heap gemaakt, zelfs letterlijk. Wanneer de JVM een letterlijke String vindt die geen equivalente verwijzing in de heap heeft, maakt de JVM een overeenkomstige String instantie op de heap en slaat deze ook een verwijzing naar de nieuw gemaakte String instantie op in de String-pool. Alle andere verwijzingen naar dezelfde letterlijke String worden vervangen door de eerder gemaakte instantie String in de heap.

Laten we het volgende voorbeeld bekijken:

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

De output van het bovenstaande is:

true
true
true
true

Diagram van Java Heap en String pool Wanneer we dubbele aanhalingstekens gebruiken om een string te maken, zoekt deze eerst naar String met dezelfde waarde in de String-pool. Als deze wordt gevonden, retourneert deze alleen de referentie, anders wordt een nieuwe String in de pool gemaakt en wordt vervolgens de referentie geretourneerd.

Met een nieuwe operator dwingen we de String-klasse echter om een nieuw String-object in de heap-ruimte te maken. We kunnen de methode intern () gebruiken om het in de pool te plaatsen of verwijzen naar een ander String-object uit een stringpool met dezelfde waarde.

De String-pool zelf wordt ook op de heap gemaakt.

Java SE 7

Vóór Java 7 werden String literals opgeslagen in de runtime constante pool in het PermGen van PermGen , dat een vaste grootte had.

De String pool woonde ook in PermGen .

Java SE 7

RFC: 6962931

In JDK 7 worden geïnterneerde tekenreeksen niet langer toegewezen aan de permanente generatie van de Java-heap, maar worden in plaats daarvan toegewezen aan het hoofdgedeelte van de Java-heap (bekend als de jonge en oude generaties), samen met de andere objecten die door de toepassing zijn gemaakt . Deze wijziging zal resulteren in meer gegevens die zich in de hoofd-Java-heap bevinden en minder gegevens in de permanente generatie, waardoor mogelijk heap-groottes moeten worden aangepast. De meeste toepassingen zullen door deze wijziging slechts relatief kleine verschillen in String.intern() zien, maar grotere toepassingen die veel klassen laden of zwaar gebruik maken van de methode String.intern() zullen grotere verschillen zien.

Hoofdletterongevoelige schakelaar

Java SE 7

switch zelf kan niet worden geparametriseerd als hoofdletterongevoelig, maar kan, indien absoluut vereist, zich ongevoelig gedragen voor de invoertekenreeks door toLowerCase() of toUpperCase :

switch (myString.toLowerCase()) {
     case "case1" :
        ...            
     break;
     case "case2" :
        ...            
     break;
}

Pas op

  • Locale kan invloed hebben op hoe veranderende cases gebeuren !
  • Zorg ervoor dat er geen hoofdletters op de labels staan - deze worden nooit uitgevoerd!


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow