Ricerca…


introduzione

Le stringhe ( java.lang.String ) sono pezzi di testo memorizzati nel tuo programma. Le stringhe non sono un tipo di dati primitivi in ​​Java , tuttavia, sono molto comuni nei programmi Java.

In Java, le stringhe sono immutabili, il che significa che non possono essere modificate. (Fare clic qui per una spiegazione più approfondita dell'immutabilità).

Osservazioni

Poiché le stringhe Java sono immutabili , tutti i metodi che manipolano una String restituiranno un nuovo oggetto String . Non cambiano la String originale. Ciò include i metodi di sottostringa e di sostituzione che i programmatori C e C ++ si aspettano di modificare l'oggetto String destinazione.


Utilizzare un StringBuilder invece di String se si desidera concatenare più di due oggetti String cui valori non possono essere determinati in fase di compilazione. Questa tecnica è più performante rispetto alla creazione di nuovi oggetti String e concatenandoli perché StringBuilder è modificabile.

StringBuffer può anche essere utilizzato per concatenare oggetti String . Tuttavia, questa classe è meno performante perché è progettata per essere thread-safe e acquisisce un mutex prima di ogni operazione. Dal momento che non si ha quasi mai bisogno di thread-safe quando si concatenano le stringhe, è meglio usare StringBuilder .

Se puoi esprimere una concatenazione di stringhe come una singola espressione, allora è meglio usare l'operatore + . Il compilatore Java convertirà un'espressione contenente + concatenazioni in una sequenza efficiente di operazioni utilizzando String.concat(...) o StringBuilder . Il consiglio di usare StringBuilder esplicitamente si applica solo quando la concatenazione coinvolge più espressioni.


Non memorizzare informazioni sensibili nelle stringhe. Se qualcuno è in grado di ottenere un dump della memoria della tua applicazione in esecuzione, sarà in grado di trovare tutti gli oggetti String esistenti e leggerne il contenuto. Ciò include oggetti String non raggiungibili e in attesa di garbage collection. Se questo è un problema, è necessario cancellare i dati sensibili delle stringhe non appena ne hai finito. Non puoi farlo con gli oggetti String poiché sono immutabili. Pertanto, è consigliabile utilizzare un oggetto char[] per conservare dati di carattere sensibili e pulirli (ad es. Sovrascriverli con caratteri '\000' ) una volta terminato.


Tutte le istanze String vengono create nell'heap, anche le istanze corrispondenti ai valori letterali stringa. La particolarità dei valori letterali delle stringhe è che la JVM garantisce che tutti i letterali uguali (ovvero che siano costituiti dagli stessi caratteri) siano rappresentati da un singolo oggetto String (questo comportamento è specificato in JLS). Questo è implementato dai caricatori di classi JVM. Quando un programma di caricamento classe carica una classe, analizza i valori letterali stringa utilizzati nella definizione di classe, ogni volta che ne rileva uno, controlla se esiste già un record nel pool di stringhe per questo valore letterale (utilizzando il valore letterale come chiave) . Se esiste già una voce per il letterale, viene utilizzato il riferimento a un'istanza di String archiviata come coppia per quel letterale. Altrimenti, viene creata una nuova istanza String e un riferimento all'istanza viene archiviato per il letterale (utilizzato come chiave) nel pool di stringhe. (Vedi anche internamento stringa ).

Il pool di stringhe viene tenuto nell'heap Java ed è soggetto alla normale garbage collection.

Java SE 7

Nelle versioni di Java precedenti a Java 7, il pool di stringhe era contenuto in una parte speciale dello heap nota come "PermGen". Questa parte è stata raccolta solo occasionalmente.

Java SE 7

In Java 7, il pool di stringhe è stato spostato da "PermGen".

Si noti che i valori letterali stringa sono implicitamente raggiungibili da qualsiasi metodo che li utilizza. Ciò significa che gli oggetti String corrispondenti possono essere raccolti solo se il codice stesso è garbage collector.


Fino a Java 8, gli oggetti String vengono implementati come un array di dati UTF-16 (2 byte per carattere). C'è una proposta in Java 9 per implementare String come array di byte con un campo flag di codifica per notare se la stringa è codificata come byte (LATIN-1) o chars (UTF-16).

Confronto di stringhe

Per confrontare le stringhe per l'uguaglianza, è necessario utilizzare i metodi equals o equalsIgnoreCase dell'oggetto String.

Ad esempio, il seguente snippet determinerà se le due istanze di String sono uguali su tutti i caratteri:

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

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

Dimostrazione dal vivo

Questo esempio li confronterà, indipendentemente dal loro caso:

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

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

Dimostrazione dal vivo

Si noti che equalsIgnoreCase non consente di specificare un Locale . Ad esempio, se si confrontano le due parole "Taki" e "TAKI" in inglese sono uguali; tuttavia, in turco sono diversi (in turco, il minuscolo I è ı ). Per casi come questo, la conversione di entrambe le stringhe in minuscolo (o maiuscolo) con Locale e il confronto con gli equals è la soluzione.

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

Dimostrazione dal vivo


Non utilizzare l'operatore == per confrontare le stringhe

A meno che tu non possa garantire che tutte le stringhe siano state internate (vedi sotto), non devi usare gli operatori == o != Per confrontare le stringhe. Questi operatori verificano effettivamente i riferimenti e, poiché più oggetti String possono rappresentare la stessa stringa, è possibile fornire una risposta errata.

Utilizzare invece il String.equals(Object) , che confronterà gli oggetti String in base ai loro valori. Per una spiegazione dettagliata, fai riferimento a Pitfall: usando == per confrontare le stringhe .


Confronto tra stringhe in un'istruzione switch

Java SE 7

A partire da Java 1.7, è possibile confrontare una variabile String a valori letterali in un'istruzione switch . Assicurati che String non sia nullo, altrimenti genererà sempre una NullPointerException . I valori vengono confrontati usando String.equals , ovvero case sensitive.

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

Dimostrazione dal vivo

Confronto di stringhe con valori costanti

Quando si confronta una String con un valore costante, è possibile inserire il valore costante sul lato sinistro degli equals per garantire che non si otterrà NullPointerException se l'altra stringa è null .

"baz".equals(foo)

Mentre foo.equals("baz") lancia una NullPointerException se foo è null , "baz".equals(foo) valuterà a false .

Java SE 7

Un'alternativa più leggibile consiste nell'utilizzare Objects.equals() , che esegue un controllo nullo su entrambi i parametri: Objects.equals(foo, "baz") .

( Nota: è discutibile se sia meglio evitare NullPointerExceptions in generale, o lasciarli accadere e quindi correggere la causa principale, vedere qui e qui . Certamente, chiamare la strategia di evitamento "best practice" non è giustificabile).

Ordinamenti di stringhe

La classe String implementa Comparable<String> con il metodo String.compareTo (come descritto all'inizio di questo esempio). Ciò rende l'ordinamento naturale degli oggetti String ordine con distinzione tra maiuscole e minuscole. La classe String fornisce una costante di Comparator<String> chiamata CASE_INSENSITIVE_ORDER adatta per l'ordinamento senza distinzione tra maiuscole e minuscole.

Confronto con stringhe internate

La specifica del linguaggio Java ( JLS 3.10.6 ) afferma quanto segue:

"Inoltre, una stringa letterale fa sempre riferimento alla stessa istanza della classe String poiché stringhe letterali o, più in generale, stringhe che rappresentano i valori delle espressioni costanti, vengono internate in modo da condividere istanze univoche, utilizzando il metodo String.intern . "

Ciò significa che è possibile confrontare i riferimenti a due valori letterali stringa usando == . Inoltre, lo stesso vale per i riferimenti agli oggetti String che sono stati prodotti utilizzando il metodo String.intern() .

Per esempio:

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

Dietro le quinte, il meccanismo di interning mantiene una tabella hash che contiene tutte le stringhe internamente ancora raggiungibili . Quando si chiama intern() su una String , il metodo cerca l'oggetto nella tabella hash:

  • Se la stringa viene trovata, tale valore viene restituito come stringa internata.
  • Altrimenti, una copia della stringa viene aggiunta alla tabella hash e tale stringa viene restituita come stringa internata.

È possibile utilizzare l'interning per consentire il confronto delle stringhe utilizzando == . Tuttavia, ci sono problemi significativi con questo; vedi Pitfall - Le stringhe Internazionali in modo che tu possa usare == è una cattiva idea per i dettagli. Non è raccomandato nella maggior parte dei casi.

Modifica del caso di caratteri all'interno di una stringa

Il tipo String fornisce due metodi per la conversione di stringhe tra maiuscole e minuscole:

  • toUpperCase per convertire tutti i caratteri in maiuscolo
  • toLowerCase per convertire tutti i caratteri in lettere minuscole

Questi metodi restituiscono entrambe le stringhe convertite come nuove istanze String : gli oggetti String originali non vengono modificati perché String è immutabile in Java. Vedi questo per saperne di più sull'immutabilità: Immutabilità di stringhe 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"

I caratteri non alfabetici, come cifre e segni di punteggiatura, non sono influenzati da questi metodi. Si noti che questi metodi possono anche trattare in modo errato determinati caratteri Unicode in determinate condizioni.


Nota : questi metodi sono sensibili alle impostazioni internazionali e potrebbero produrre risultati imprevisti se utilizzati su stringhe che devono essere interpretate indipendentemente dalle impostazioni internazionali. Gli esempi sono identificatori di linguaggio di programmazione, chiavi di protocollo e tag HTML .

Ad esempio, "TITLE".toLowerCase() in una locale turca restituisce " tıtle ", dove ı (\u0131) è il carattere LATIN SMALL LETTER DOTLESS I. Per ottenere risultati corretti per le stringhe insensibili della locale, passare Locale.ROOT come parametro al metodo di conversione caso corrispondente (ad es toLowerCase(Locale.ROOT) o toUpperCase(Locale.ROOT) ).

Anche se l'uso di Locale.ENGLISH è corretto anche per la maggior parte dei casi, il modo in cui la lingua è invariata è Locale.ROOT .

Un elenco dettagliato dei caratteri Unicode che richiedono un involucro speciale può essere trovato sul sito Web del Consorzio Unicode .

Modifica del caso di un carattere specifico all'interno di una stringa ASCII:

Per cambiare il caso di un carattere specifico di una stringa ASCII, è possibile utilizzare l'algoritmo seguente:

passi:

  1. Dichiara una stringa.
  2. Inserisci la stringa.
  3. Converti la stringa in un array di caratteri.
  4. Inserisci il carattere che deve essere cercato.
  5. Cerca il personaggio nell'array di caratteri.
  6. Se trovato, controlla se il carattere è in minuscolo o maiuscolo.
    • Se è maiuscolo, aggiungi 32 al codice ASCII del carattere.
    • Se Minuscolo, sottrai 32 dal codice ASCII del carattere.
  7. Cambia il carattere originale dall'array di caratteri.
  8. Converti nuovamente l'array di caratteri nella stringa.

Voilà, il caso del personaggio è cambiato.

Un esempio del codice dell'algoritmo è:

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

Trovare una stringa all'interno di un'altra stringa

Per verificare se una particolare stringa a è contenuta in una stringa b oppure no, possiamo usare il metodo String.contains() con la seguente sintassi:

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

Il metodo String.contains() può essere utilizzato per verificare se è possibile trovare un CharSequence nella stringa. Il metodo cerca la stringa a nella stringa b in modo maiuscole e minuscole.

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

Demo live su Ideone


Per trovare la posizione esatta in cui una stringa inizia all'interno di un'altra stringa, utilizzare 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

Demo live su Ideone

Il metodo String.indexOf() restituisce il primo indice di un char o di una String in un'altra String . Il metodo restituisce -1 se non viene trovato.

Nota : il metodo String.indexOf() è sensibile al maiuscolo / minuscolo.

Esempio di ricerca che ignora il caso:

String str1 = "Hello World";
String str2 = "wOr";
str1.indexOf(str2);                               // -1
str1.toLowerCase().contains(str2.toLowerCase());  // true
str1.toLowerCase().indexOf(str2.toLowerCase());   // 6

Demo live su Ideone

Ottenere la lunghezza di una stringa

Per ottenere la lunghezza di un oggetto String , chiamare il metodo length() su di esso. La lunghezza è uguale al numero di unità di codice UTF-16 (caratteri) nella stringa.

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

Demo live su Ideone

Un char in una stringa è il valore UTF-16. I codepoint Unicode i cui valori sono ≥ 0x1000 (ad esempio, la maggior parte degli emoji) utilizzano due posizioni char. Per contare il numero di punti di codice Unicode in una stringa, indipendentemente dal fatto che ciascun punto di codice rientri in un valore di char UTF-16, è possibile utilizzare il metodo codePointCount :

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

È inoltre possibile utilizzare un flusso di codepoint, come di Java 8:

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

sottostringhe

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

Le sottostringhe possono anche essere applicate per tagliare e aggiungere / sostituire caratteri nella sua stringa originale. Ad esempio, hai affrontato una data cinese contenente caratteri cinesi, ma vuoi memorizzarla come una stringa di data in formato well.

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

Il metodo della sottostringa estrae un pezzo di una String . Quando viene fornito un parametro, il parametro è l'inizio e il pezzo si estende fino alla fine della String . Quando vengono dati due parametri, il primo parametro è il carattere di partenza e il secondo parametro è l'indice del carattere subito dopo la fine (il carattere dell'indice non è incluso). Un modo semplice per verificare è la sottrazione del primo parametro dal secondo dovrebbe fornire la lunghezza prevista della stringa.

Java SE 7

Nelle versioni JDK <7u6 il metodo della substring crea un'istanza di una String che condivide lo stesso char[] backup char[] della String originale e dispone dei campi di offset e count interni impostati per l'inizio e la lunghezza del risultato. Tale condivisione può causare perdite di memoria, che possono essere prevenute chiamando la new String(s.substring(...)) per forzare la creazione di una copia, dopo di che char[] può essere garbage collection.

Java SE 7

Da JDK 7u6 il metodo della substring copia sempre l'intero array char[] sottostante, rendendo la complessità lineare rispetto alla costante precedente ma garantendo l'assenza di perdite di memoria contemporaneamente.

Ottenere l'ennesimo carattere in una stringa

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"

Per ottenere l'ennesimo carattere in una stringa, chiama semplicemente charAt(n) su una String , dove n è l'indice del carattere che desideri recuperare

NOTA: l' indice n inizia a 0 , quindi il primo elemento è n = 0.

Separatore di nuove linee indipendente dalla piattaforma

Poiché il nuovo separatore di linee varia da piattaforma a piattaforma (ad es. \n su sistemi di tipo Unix o \r\n su Windows) è spesso necessario avere un modo indipendente dalla piattaforma di accedervi. In Java può essere recuperato da una proprietà di sistema:

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

Poiché il nuovo separatore di righe è così comunemente necessario, da Java 7 su un metodo di scelta rapida che restituisce esattamente lo stesso risultato del codice precedente è disponibile:

System.lineSeparator()

Nota : poiché è molto improbabile che il nuovo separatore di riga cambi durante l'esecuzione del programma, è consigliabile archiviarlo in una variabile finale statica anziché recuperarlo dalla proprietà di sistema ogni volta che è necessario.

Quando si utilizza String.format , utilizzare %n anziché \n o '\ r \ n' per generare un nuovo separatore di riga indipendente dalla piattaforma.

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

Aggiunta del metodo toString () per oggetti personalizzati

Supponiamo di aver definito la seguente classe Person :

public class Person {

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

Se istanziate un nuovo oggetto Person :

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

e più avanti nel tuo codice usi la seguente dichiarazione per stampare l'oggetto:

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

Demo live su Ideone

otterrai un risultato simile al seguente:

Person@7ab89d

Questo è il risultato dell'implementazione del metodo toString() definito nella classe Object , una superclasse di Person . La documentazione di Object.toString() afferma:

Il metodo toString per l'oggetto classe restituisce una stringa composta dal nome della classe di cui l'oggetto è un'istanza, il carattere at-sign `@ 'e la rappresentazione esadecimale senza firma del codice hash dell'oggetto. In altre parole, questo metodo restituisce una stringa uguale al valore di:

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

Quindi, per un output significativo, dovrai sovrascrivere il metodo toString() :

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

Ora l'output sarà:

My name is John and my age is 25

Puoi anche scrivere

System.out.println(person);

Demo live su Ideone

Infatti, println() richiama implicitamente il metodo toString sull'oggetto.

Spaccare le corde

È possibile dividere una String su un particolare carattere di delimitazione o un'espressione regolare , è possibile utilizzare il metodo String.split() con la seguente firma:

public String[] split(String regex)

Si noti che la delimitazione del carattere o dell'espressione regolare viene rimossa dalla matrice di stringhe risultante.

Esempio utilizzando il carattere di delimitazione:

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

Esempio usando l'espressione regolare:

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

Puoi anche dividere direttamente un valore letterale String :

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

Avvertenza : non dimenticare che il parametro viene sempre considerato come un'espressione regolare.

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

Nell'esempio precedente . viene considerato come il carattere jolly di espressione regolare che corrisponde a qualsiasi carattere e poiché ogni carattere è un delimitatore, il risultato è un array vuoto.


Divisione basata su un delimitatore che è un meta-carattere regex

I seguenti personaggi sono considerati speciali (detti anche meta-caratteri) in espressioni regolari

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

Per dividere una stringa in base a uno dei delimitatori sopra indicati, è necessario Pattern.quote() l' escape usando \\ o utilizzare Pattern.quote() :

  • Utilizzando Pattern.quote() :

     String s = "a|b|c";
     String regex = Pattern.quote("|");
     String[] arr = s.split(regex);
    
  • Sfuggire ai caratteri speciali:

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

Split rimuove i valori vuoti

split(delimiter) per default rimuove le stringhe vuote finali dall'array dei risultati. Per disattivare questo meccanismo, è necessario utilizzare la versione di split(delimiter, limit) con limite impostato su valore negativo come

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

split(regex) restituisce internamente il risultato di split(regex, 0) .

Il parametro limit controlla il numero di volte in cui il pattern è applicato e quindi influenza la lunghezza dell'array risultante.
Se il limite n è maggiore di zero, il pattern verrà applicato al massimo n - 1 volte, la lunghezza dell'array non sarà maggiore di n e l'ultima voce dell'array conterrà tutti gli input oltre l'ultimo delimitatore corrispondente.
Se n è negativo, il pattern verrà applicato il maggior numero possibile di volte e l'array può avere una lunghezza qualsiasi.
Se n è zero, il pattern verrà applicato il maggior numero di volte possibile, l'array può avere una lunghezza qualsiasi e le stringhe vuote verranno eliminate.


Divisione con StringTokenizer

Oltre al metodo split() , le stringhe possono anche essere suddivise usando StringTokenizer .

StringTokenizer è ancora più restrittivo di String.split() , e anche un po 'più difficile da usare. È essenzialmente progettato per estrarre token delimitati da un set fisso di caratteri (dati come String ). Ogni personaggio fungerà da separatore. A causa di questa restrizione, è circa il doppio della velocità di String.split() .

I set di caratteri predefiniti sono spazi vuoti ( \t\n\r\f ). L'esempio seguente stamperà ogni parola separatamente.

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

Questo verrà stampato:

the
lazy 
fox 
jumped 
over 
the 
brown 
fence

È possibile utilizzare diversi set di caratteri per la separazione.

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

Questo verrà stampato:

j
mp 
d ov
r

Unione di stringhe con un delimitatore

Java SE 8

Un array di stringhe può essere unito usando il metodo statico String.join() :

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

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

Allo stesso modo, c'è un metodo String.join() sovraccarico per Iterable s.


Per avere un controllo dettagliato sull'unione , è possibile utilizzare la classe StringJoiner :

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

Per unire un flusso di stringhe, puoi utilizzare il raccoglitore di join:

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

C'è anche un'opzione per definire prefisso e suffisso :

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

Inversione di archi

Ci sono un paio di modi in cui puoi invertire una stringa per farla tornare indietro.

  1. StringBuilder / StringBuffer:

     String code = "code";
     System.out.println(code);
    
     StringBuilder sb = new StringBuilder(code); 
     code = sb.reverse().toString();
    
     System.out.println(code);
    
  2. Array di caratteri:

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

Conteggio delle occorrenze di una sottostringa o di un carattere in una stringa

countMatches metodo countMatches di org.apache.commons.lang3.StringUtils viene in genere utilizzato per contare le occorrenze di una sottostringa o di un carattere in una 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

In caso contrario, per le stesse API Java standard è possibile utilizzare le espressioni regolari:

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

Concatenazione di stringhe e StringBuilder

La concatenazione di stringhe può essere eseguita usando l'operatore + . Per esempio:

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

Normalmente un'implementazione del compilatore eseguirà la suddetta concatenazione usando metodi che coinvolgono un StringBuilder sotto il cofano. Una volta compilato, il codice sarà simile al seguente:

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

StringBuilder ha diversi metodi di overloading per aggiungere tipi diversi, ad esempio, per aggiungere un int posto di una String . Ad esempio, un'implementazione può convertire:

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

al seguente:

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

Gli esempi sopra illustrano una semplice operazione di concatenazione che viene effettivamente eseguita in un singolo punto nel codice. La concatenazione implica una singola istanza di StringBuilder . In alcuni casi, una concatenazione viene eseguita in modo cumulativo come in un ciclo:

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

In questi casi, l'ottimizzazione del compilatore di solito non viene applicata e ogni iterazione creerà un nuovo oggetto StringBuilder . Questo può essere ottimizzato trasformando esplicitamente il codice per utilizzare un singolo StringBuilder :

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

Un StringBuilder verrà inizializzato con uno spazio vuoto di soli 16 caratteri. Se si sa in anticipo che si costruiscono stringhe più grandi, può essere utile inizializzarlo con dimensioni sufficienti in anticipo, in modo che il buffer interno non debba essere ridimensionato:

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

Se stai producendo molte stringhe, è consigliabile riutilizzare StringBuilder :

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

Se (e solo se) più thread scrivono nello stesso buffer, utilizzare StringBuffer , che è una versione synchronized di StringBuilder . Ma poiché solitamente un solo thread scrive su un buffer, di solito è più veloce usare StringBuilder senza sincronizzazione.

Usando il metodo concat ():

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

Ciò restituisce una nuova stringa che è stringa1 con stringa2 aggiunta ad essa alla fine. Puoi anche usare il metodo concat () con stringhe letterali, come in:

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

Sostituzione di parti di stringhe

Due modi per sostituire: regex o per corrispondenza esatta.

Nota: l'oggetto String originale sarà invariato, il valore restituito mantiene la stringa modificata.

Corrispondenza esatta

Sostituisci un singolo carattere con un altro singolo carattere:

String replace(char oldChar, char newChar) 

Restituisce una nuova stringa risultante dalla sostituzione di tutte le occorrenze di oldChar in questa stringa con newChar.

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

Risultato:

WoWcorn

Sostituisci la sequenza di caratteri con un'altra sequenza di caratteri:

String replace(CharSequence target, CharSequence replacement) 

Sostituisce ogni sottostringa di questa stringa che corrisponde alla sequenza di destinazione letterale con la sequenza di sostituzione letterale specificata.

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

Risultato:

metallica petallica et al.

regex

Nota : il raggruppamento usa il carattere $ per fare riferimento ai gruppi, ad esempio $1 .

Sostituisci tutte le partite:

String replaceAll(String regex, String replacement) 

Sostituisce ogni sottostringa di questa stringa che corrisponde all'espressione regolare data con la sostituzione fornita.

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

Risultato:

spiral metallica petallica et al.

Sostituisci solo la prima partita:

String replaceFirst(String regex, String replacement) 

Sostituisce la prima sottostringa di questa stringa che corrisponde all'espressione regolare data con la sostituzione specificata

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

Risultato:

spiral metallica petal et al.

Rimuovi spazi bianchi dall'inizio e alla fine di una stringa

Il metodo trim() restituisce una nuova stringa con gli spazi bianchi iniziali e finali rimossi.

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

Se si trim una stringa che non ha spazi bianchi da rimuovere, verrà restituita la stessa istanza String.

Si noti che il metodo trim() ha la propria nozione di spazio bianco , che differisce dalla nozione utilizzata dal metodo Character.isWhitespace() :

  • Tutti i caratteri di controllo ASCII con i codici da U+0000 a U+0020 sono considerati spazi bianchi e vengono rimossi da trim() . Questo include U+0020 'SPACE' , U+0009 'CHARACTER TABULATION' , U+000A 'LINE FEED' e U+000D 'CARRIAGE RETURN' , ma anche i caratteri come U+0007 'BELL' .

  • Gli spazi bianchi Unicode come U+00A0 'NO-BREAK SPACE' o U+2003 'EM SPACE' non sono riconosciuti da trim() .

Pool di stringhe e archiviazione heap

Come molti oggetti Java, tutte le istanze String vengono create sullo heap, anche letterali. Quando la JVM trova un valore letterale String che non ha riferimenti equivalenti nell'heap, la JVM crea un'istanza String corrispondente nell'heap e memorizza anche un riferimento all'istanza String appena creata nel pool String. Qualsiasi altro riferimento allo stesso letterale String viene sostituito con l'istanza String precedentemente creata nell'heap.

Diamo un'occhiata al seguente esempio:

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

L'output di quanto sopra è:

true
true
true
true

Diagramma di heap Java e pool di stringhe Quando si usano le doppie virgolette per creare una stringa, prima cerca String con lo stesso valore nel pool String, se trovato restituisce solo il riferimento altrimenti crea una nuova stringa nel pool e quindi restituisce il riferimento.

Tuttavia, utilizzando un nuovo operatore, imponiamo la classe String per creare un nuovo oggetto String nello spazio heap. Possiamo usare il metodo intern () per metterlo nel pool o fare riferimento ad un altro oggetto String dal pool di stringhe con lo stesso valore.

Anche il pool di stringhe stesso viene creato nell'heap.

Java SE 7

Prima di Java 7, i valori letterali String venivano memorizzati nel pool costante di runtime nell'area del metodo di PermGen , che aveva una dimensione fissa.

Il pool di stringhe risiedeva anche in PermGen .

Java SE 7

RFC: 6962931

In JDK 7, le stringhe internate non sono più allocate nella generazione permanente dell'heap Java, ma sono allocate nella parte principale dell'heap Java (noto come generazioni giovani e meno recenti), insieme agli altri oggetti creati dall'applicazione . Questo cambiamento comporterà più dati residenti nell'heap principale di Java e meno dati nella generazione permanente e, pertanto, potrebbe richiedere la regolazione delle dimensioni dell'heap. La maggior parte delle applicazioni vedrà solo differenze relativamente piccole nell'utilizzo dell'heap a causa di questa modifica, ma applicazioni più grandi che caricano molte classi o fanno un uso massiccio del metodo String.intern() vedranno differenze più significative.

Interruttore non sensibile al maiuscolo / minuscolo

Java SE 7

switch stesso non può essere parametrizzato senza distinzione tra maiuscole e minuscole, ma se strettamente necessario, può comportarsi in modo insensibile alla stringa di input utilizzando toLowerCase() o toUpperCase :

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

diffidare

  • Locale potrebbero influenzare il modo in cui i casi cambiano !
  • Bisogna fare attenzione a non avere caratteri maiuscoli nelle etichette - quelli non verranno mai eseguiti!


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow