Java Language
strings
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.
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.
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.
}
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.
}
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
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
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;
}
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.
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 methodeString.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:
- Declareer een string.
- Voer de string in.
- Converteer de tekenreeks naar een tekenreeks.
- Voer het teken in dat moet worden doorzocht.
- Zoek naar het karakter in de character array.
- 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.
- Verander het originele karakter uit de Character array.
- 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
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
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
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
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.
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.
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")
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());
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);
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
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.
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));
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
totU+0020
worden als witruimte beschouwd en worden verwijderd doortrim()
. Dit omvatU+0020 'SPACE'
,U+0009 'CHARACTER TABULATION'
,U+000A 'LINE FEED'
enU+000D 'CARRIAGE RETURN'
karakters, maar ook de karakters zoalsU+0007 'BELL'
.Unicode witruimte zoals
U+00A0 'NO-BREAK SPACE'
ofU+2003 'EM SPACE'
worden niet herkend doortrim()
.
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
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.
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
.
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 methodeString.intern()
zullen grotere verschillen zien.
Hoofdletterongevoelige schakelaar
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!