JavaRush /Java Blog /Random-IT /Introduzione a String, StringBuffer e StringBuilder in Ja...

Introduzione a String, StringBuffer e StringBuilder in Java

Pubblicato nel gruppo Random-IT
Esistono tre classi in Java per lavorare con dati di testo: String , StringBuffer e StringBuilder . Ogni sviluppatore incontra il primo all'inizio dell'apprendimento della lingua. E i restanti due? Quali sono le loro differenze e quando è meglio utilizzare l'una o l'altra classe? In generale, la differenza tra loro è piccola, ma è meglio capire tutto nella pratica :) Introduzione a String, StringBuffer e StringBuilder in Java - 1

Classe di stringhe

Questa classe rappresenta una sequenza di caratteri. Tutti i valori letterali stringa definiti nei programmi, come "This is String" sono istanze della classe String. La stringa ha due caratteristiche fondamentali:
  • questa è una classe immutabile
  • questa è la lezione finale
In generale, la classe String non può avere figli ( final) e le istanze della classe non possono essere modificate dopo la creazione ( immutable). Ciò offre alla classe String diversi importanti vantaggi:
  1. A causa dell'immutabilità, l'hashcode di un'istanza della classe String viene memorizzato nella cache. Non è necessario valutarlo ogni volta perché i valori del campo dell'oggetto non cambieranno mai dopo la sua creazione. Ciò garantisce prestazioni elevate quando si utilizza questa classe come chiave per HashMap.

  2. La classe String può essere utilizzata in un ambiente multi-thread senza sincronizzazione aggiuntiva.

  3. Un'altra caratteristica della classe String è che sovraccarica l' +operatore " " in Java. Pertanto, la concatenazione (addizione) di stringhe è abbastanza semplice:


public static void main(String[] args) {
    String command = "Follow" + " " + "the" + " " + "white" + " " + "rabbit";
    System.out.println(command); // Follow the white rabbit
}
Dietro le quinte, la concatenazione delle stringhe viene eseguita dalla classe StringBuilder o StringBuffer (a discrezione del compilatore) e da un metodo append(parleremo di queste classi un po' più tardi). Se aggiungiamo istanze della classe String con istanze di altre classi, queste ultime si ridurranno ad una rappresentazione di stringa:

public static void main(String[] args) {       
    Boolean b = Boolean.TRUE;
    String result = "b is " + b;    
    System.out.println(result); //b is true
}
Questa è un'altra proprietà interessante della classe String: gli oggetti di qualsiasi classe possono essere convertiti in una rappresentazione di stringa utilizzando il metodo toString()definito nella classe Objected ereditato da tutte le altre classi. Spesso il metodo toString() su un oggetto viene chiamato implicitamente. Ad esempio, quando visualizziamo qualcosa sullo schermo o aggiungiamo una String a un oggetto di un'altra classe. La classe String ha un'altra caratteristica. Tutti i valori letterali stringa definiti nel codice Java, come "asdf", vengono memorizzati nella cache in fase di compilazione e aggiunti al cosiddetto pool di stringhe. Se eseguiamo il seguente codice:

String a = "Wake up, Neo";
String b = "Wake up, Neo";

System.out.println(a == b);
Vedremo true nella console perché le variabili faranno aeffettivamente briferimento alla stessa istanza della classe String che è stata aggiunta allo string pool in fase di compilazione. Cioè, non vengono create istanze diverse della classe con lo stesso valore e la memoria viene salvata.

Screpolatura:

Non è difficile intuire che la classe String è necessaria principalmente per lavorare con le stringhe. Ma in alcuni casi, le funzionalità di cui sopra della classe String possono trasformarsi da vantaggi in svantaggi. Una volta create le stringhe nel codice Java, spesso vengono eseguite molte operazioni su di esse:
  • convertire stringhe in registri diversi;
  • estrazione di sottostringhe;
  • concatenazione;
  • eccetera.
Diamo un'occhiata a questo codice:

public static void main(String[] args) {

    String s = " Wake up, Neo! ";
    s = s.toUpperCase();
    s = s.trim();

    System.out.println("\"" + s + "\"");
}
A prima vista, sembra che abbiamo appena tradotto la frase “Svegliati, Neo!” in maiuscolo, rimosso gli spazi aggiuntivi da questa stringa e racchiuso tra virgolette. Infatti, a causa dell'immutabilità della classe String, a seguito di ogni operazione vengono create nuove istanze di stringa e quelle vecchie vengono scartate, generando una grande quantità di spazzatura. Come evitare lo spreco di memoria?

Classe StringBuffer

Per gestire la creazione di spazzatura temporanea dovuta a modifiche a un oggetto String, è possibile utilizzare la classe StringBuffer. Questa è mutableuna classe, ad es. variabile. Un oggetto della classe StringBuffer può contenere un insieme specifico di caratteri, la cui lunghezza e valore possono essere modificati chiamando determinati metodi. Vediamo come funziona questa classe. Per creare un nuovo oggetto, utilizzare uno dei suoi costruttori, ad esempio:
  • StringBuffer() - creerà un oggetto vuoto (senza caratteri).
  • StringBuffer(String str) - creerà un oggetto basato sulla variabile str (contenente tutti i caratteri di str nella stessa sequenza)
Pratica:

StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Not empty");
La concatenazione di stringhe tramite StringBuffer in Java viene eseguita utilizzando append. In generale, il metodo appendnella classe StringBuffer è sovraccaricato in modo tale da poter accettare quasi tutti i tipi di dati:

public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2));
    sb.append("; ");
    sb.append(false);
    sb.append("; ");
    sb.append(Arrays.asList(1,2,3));
    sb.append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3]; 
}
Il metodo appendrestituisce l'oggetto su cui è stato chiamato (come molti altri metodi), che gli consente di essere chiamato in una “catena”. L'esempio sopra può essere scritto in questo modo:

public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2))
            .append("; ")
            .append(false)
            .append("; ")
            .append(Arrays.asList(1,2,3))
            .append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
La classe StringBuffer dispone di numerosi metodi per lavorare con le stringhe. Elenchiamo i principali:
  • delete(int start, int end)— cancella una sottostringa di caratteri a partire dalla posizione start, finendoend
  • deleteCharAt(int index)— cancella il carattere in posizioneindex
  • insert(int offset, String str)— inserisce una riga strnella posizione offset. Il metodo insertè inoltre sovraccaricato e può accettare argomenti diversi
  • replace(int start, int end, String str)- sostituirà tutti i caratteri da una startposizione all'altra endconstr
  • reverse()— inverte l'ordine di tutti i caratteri
  • substring(int start)- restituirà una sottostringa a partire dalla posizione start
  • substring(int start, int end)- restituirà una sottostringa a partire da una posizione startall'altraend
Un elenco completo di metodi e costruttori si trova nella documentazione ufficiale . Come funzionano i metodi di cui sopra? Vediamo in pratica:

public static void main(String[] args) {
     String numbers = "0123456789";

     StringBuffer sb = new StringBuffer(numbers);

     System.out.println(sb.substring(3)); // 3456789
     System.out.println(sb.substring(4, 8)); // 4567
     System.out.println(sb.replace(3, 5, "ABCDE")); // 012ABCDE56789

     sb = new StringBuffer(numbers);
     System.out.println(sb.reverse()); // 9876543210
     sb.reverse(); // Return the original order

     sb = new StringBuffer(numbers);
     System.out.println(sb.delete(5, 9)); // 012349
     System.out.println(sb.deleteCharAt(1)); // 02349
     System.out.println(sb.insert(1, "One")); // 0One2349
    }

Vantaggi:

  1. Come già accennato, StringBuffer è una classe mutabile, quindi lavorare con essa non crea la stessa quantità di spazzatura di memoria di String. Pertanto, se si apportano molte modifiche alle stringhe, è meglio utilizzare StringBuffer.

  2. StringBuffer è una classe thread-safe. I suoi metodi sono sincronizzati e le istanze possono essere utilizzate da più thread contemporaneamente.

Screpolatura:

Da un lato, la sicurezza del thread è un vantaggio della classe e, dall'altro, è uno svantaggio. I metodi sincronizzati sono più lenti dei metodi non sincronizzati. È qui che entra in gioco StringBuilder. Scopriamo che tipo di classe Java è - StringBuilder, quali metodi ha e quali sono le sue caratteristiche.

Classe StringBuilder

StringBuilder in Java è una classe che rappresenta una sequenza di caratteri. È molto simile a StringBuffer in tutto tranne che per la sicurezza del thread. StringBuilder fornisce un'API simile a StringBuffer. Dimostriamolo utilizzando un esempio già familiare, sostituendo la dichiarazione di variabili da StringBufer a StringBuilder:

public static void main(String[] args) {
    String numbers = "0123456789";

    StringBuilder sb = new StringBuilder(numbers);

    System.out.println(sb.substring(3)); //3456789
    System.out.println(sb.substring(4, 8)); //4567
    System.out.println(sb.replace(3, 5, "ABCDE")); //012ABCDE56789

    sb = new StringBuilder(numbers);
    System.out.println(sb.reverse()); //9876543210
    sb.reverse(); // Return the original order

    sb = new StringBuilder(numbers);
    System.out.println(sb.delete(5, 9)); //012349
    System.out.println(sb.deleteCharAt(1)); //02349
    System.out.println(sb.insert(1, "One")); //0One2349
}
L'unica differenza è che StringBuffer è thread-safe e tutti i suoi metodi sono sincronizzati, mentre StringBuilder no. Questa è l'unica caratteristica. StringBuilder in Java è più veloce di StringBuffer a causa della mancata sincronizzazione dei metodi. Pertanto, nella maggior parte dei casi, tranne che in un ambiente multi-thread, è preferibile utilizzare StringBuilder per un programma Java. Riassumiamo il tutto in una tabella comparativa delle tre classi:

String vs StringBuffer vs StringBuilder

Corda StringBuffer StringBuilder
Mutevolezza Immutable(NO) mutable(SÌ) mutable(SÌ)
Estensibilità final(NO) final(NO) final(NO)
Sicurezza del filo Sì, a causa dell'immutabilità Sì, grazie alla sincronizzazione NO
Quando usare Quando si lavora con stringhe che verranno modificate raramente Quando si lavora con stringhe che verranno modificate frequentemente in un ambiente multi-thread Quando si lavora con stringhe che verranno modificate frequentemente in un ambiente a thread singolo
Puoi studiare questo argomento in modo più dettagliato al secondo livello della ricerca Java Multithreading nel corso JavaRush:
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION