String, StringBuffer i StringBuilder

Proszę powiedz mi sytuację w czasie rzeczywistym, aby porównać String, StringBuffer, i StringBuilder?

Author: Radiodef, 2010-06-04

11 answers

Różnica Zmienności:

String jest niezmienne, jeśli spróbujesz zmienić ich wartości, zostanie utworzony inny obiekt, podczas gdy StringBuffer i StringBuilder mutowalne , aby mogły zmienić swoje wartości.

Thread-Safety Difference:

Różnica między StringBuffer A StringBuilder jest taka, że StringBuffer jest bezpieczna dla wątku. Jeśli więc aplikacja musi być uruchomiona tylko w jednym wątku, to lepiej jest użyć StringBuilder. StringBuilder jest bardziej wydajny niż StringBuffer.

Sytuacje:

  • jeśli twój łańcuch znaków nie zmieni się, Użyj klasy łańcuchów, ponieważ obiekt String jest niezmienny.
  • jeśli twój ciąg znaków może się zmienić (przykład: wiele logiki i operacji w konstrukcji łańcucha) i będzie dostępny tylko z jednego wątku, użycie StringBuilder jest wystarczająco dobre.
  • jeśli twój ciąg znaków może się zmienić i będzie dostępny z wielu wątków, użyj StringBuffer Ponieważ StringBuffer jest synchroniczny, więc masz gwint-bezpieczeństwo.
 327
Author: bakkal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-19 21:26:24
  • używasz String gdy odpowiednia jest niezmienna struktura; uzyskanie nowego ciągu znaków z String może wiązać się z niedopuszczalną karą za wydajność, zarówno w czasie procesora, jak i w pamięci (uzyskanie podciągów jest wydajne, ponieważ dane nie są kopiowane, ale oznacza to, że potencjalnie dużo większa ilość danych może pozostać przydzielona).
  • używasz StringBuilder Kiedy trzeba utworzyć zmienną sekwencję znaków, zwykle w celu połączenia kilku sekwencji znaków razem.
  • używasz StringBuffer w tych samych okolicznościach można użyć StringBuilder, ale gdy zmiany w łańcuchu muszą być zsynchronizowane (ponieważ kilka wątków odczytuje / modyfikuje bufor Łańcuchowy).

Zobacz przykład tutaj .

 45
Author: Artefacto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 14:33:06

Podstawy:

String jest niezmienną klasą, nie można jej zmienić. StringBuilder jest zmienną klasą, do której można dodawać, zastępować lub usuwać znaki i ostatecznie konwertować na String StringBuffer jest oryginalną zsynchronizowaną wersją StringBuilder

Powinieneś preferować StringBuilder we wszystkich przypadkach, w których dostęp do obiektu ma tylko jeden wątek.

Szczegóły:

Zauważ również, że StringBuilder/Buffers nie są magiczne, po prostu używają tablicy jako backing object i ta tablica musi być ponownie przydzielona, gdy tylko się zapełni. Upewnij się, że Twoje obiekty StringBuilder/Buffer są wystarczająco duże, aby nie musiały być stale zmieniane przy każdym wywołaniu .append().

Zmiana rozmiaru może być bardzo zdegenerowana. Zasadniczo zmienia rozmiar tablicy nośnej do 2 razy swojego obecnego rozmiaru za każdym razem, gdy trzeba ją rozszerzyć. Może to spowodować przydzielenie dużej ilości pamięci RAM i nieużywanie jej, gdy klasy StringBuilder/Buffer zaczną rosnąć duży.

W Javie String x = "A" + "B"; używa StringBuilder Za kulisami. Tak więc w prostych przypadkach nie ma korzyści z deklarowania własnej. Ale jeśli budujesz String obiekty, które są duże, powiedzmy mniej niż 4K, deklarowanie StringBuilder sb = StringBuilder(4096); jest o wiele bardziej efektywne niż konkatenacja lub użycie domyślnego konstruktora , który ma tylko 16 znaków. Jeśli twoja String ma być mniejsza niż 10K, zainicjuj ją konstruktorem do 10K, aby było bezpieczne. Ale jeśli jest initialize do 10k to piszesz 1 znak większy niż 10K, zostanie ponownie przydzielony i skopiowany do tablicy 20k. Więc inicjalizacja wysokiego jest lepsza niż niskiego.

W przypadku automatycznej zmiany rozmiaru, na 17. znaku tablica zapasowa zostaje ponownie przydzielona i skopiowana do 32 znaków, na 33. znaku dzieje się to ponownie i można ponownie przydzielać i skopiować tablicę do 64 znaków. Możesz zobaczyć, jak to degeneruje się do partii re-alokacji i kopii, czego tak naprawdę starasz się uniknąć używając StringBuilder/Buffer w miejsce.

To jest z kodu źródłowego JDK 6 dla AbstractStringBuilder

   void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
        value = Arrays.copyOf(value, newCapacity);
    }

Najlepszą praktyką jest zainicjowanie StringBuilder/Buffer trochę większego, niż myślisz, że będziesz potrzebował, jeśli nie wiesz od razu, jak duży będzie String, ale możesz się domyślić. Jedna alokacja nieco więcej pamięci niż potrzebujesz będzie lepsza niż wiele ponownych alokacji i kopii.

Uważaj również na inicjalizację a StringBuilder/Buffer z String, ponieważ przydziela ona tylko rozmiar łańcucha + 16 znaków, co w większości przypadków po prostu rozpocznie zdegenerowany cykl re-alokacji i kopiowania, którego próbujesz uniknąć. Poniżej znajduje się kod źródłowy Java 6.

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

Jeśli przypadkiem trafisz na instancję StringBuilder/Buffer, której nie stworzyłeś i nie możesz kontrolować wywoływanego konstruktora, istnieje sposób na uniknięcie zdegenerowanego zachowania realokacji i kopiowania. Call .ensureCapacity() z rozmiarem, który chcesz zapewnić wynik String będzie pasować.

Alternatywy:

Tak dla przypomnienia, jeśli robisz naprawdę ciężkie String Budowa i manipulacja, istnieje znacznie bardziej zorientowana na wydajność alternatywa o nazwie {77]} liny {40]}.

Inną alternatywą jest utworzenie implementacji StringList przez podklasowanie ArrayList<String> i dodanie liczników do śledzenia liczby znaków na każdej .append() i innych operacji na liście, a następnie nadpisanie .toString(), aby utworzyć StringBuilder z listy. dokładny rozmiar, którego potrzebujesz, Pętla przez Listę i zbuduj wyjście, możesz nawet uczynić StringBuilder zmienną instancji i "buforować" wyniki .toString() i tylko ponownie wygenerować ją, gdy coś się zmieni.

Nie zapominaj również o String.format() podczas budowania stałych, sformatowanych danych wyjściowych, które mogą być optymalizowane przez kompilator w miarę ich ulepszania.

 27
Author: 12 revs, 2 users 95%user177800,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-17 16:49:05

Masz na myśli konkatenację?

Przykład ze świata rzeczywistego: chcesz utworzyć nowy ciąg znaków spośród wielu innych.

Na przykład, aby wysłać wiadomość:

String

String s = "Dear " + user.name + "<br>" + 
" I saw your profile and got interested in you.<br>" +
" I'm  " + user.age + "yrs. old too"

StringBuilder

String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" ) 
          .append(" I saw your profile and got interested in you.<br>") 
          .append(" I'm  " ).append( user.age ).append( "yrs. old too")
          .toString()

Lub

String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as  fuzzy lollipop points out.

StringBuffer (składnia jest dokładnie taka jak w Stringbuilderze, efekty są różne)

O

StringBuffer vs. StringBuilder

Pierwszy jest zsynchronizowany, a później nie.

Więc jeśli wywołanie go kilka razy w jednym wątku (co stanowi 90% przypadków), StringBuilder uruchomi dużo {36]} szybciej, ponieważ nie zatrzyma się, aby sprawdzić, czy posiada blokadę wątku.

Dlatego zaleca się użycie StringBuilder (o ile oczywiście nie masz dostępu do więcej niż jednego wątku w tym samym czasie, co jest rzadkością)

String concatenation (using the + operator ) may be optimized by the compiler to use StringBuilder Under, so, it not longer something to worry about, in The elder days of Java, to było coś, co wszyscy mówią, że należy unikać za wszelką cenę, ponieważ każda konkatenacja tworzy nowy obiekt String. Nowoczesne Kompilatory już tego nie robią, ale nadal dobrą praktyką jest używanie StringBuilder zamiast tego na wypadek, gdybyś używał "starego" kompilatora.

Edit

Tylko dla ciekawskich, to jest to, co kompilator robi dla tej klasy:

class StringConcatenation {
    int x;
    String literal = "Value is" + x;
    String builder = new StringBuilder().append("Value is").append(x).toString();
}

Javap-C StringConcatenation

Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;

java.lang.String literal;

java.lang.String builder;

StringConcatenation();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new #2; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   12:  ldc #4; //String Value is
   14:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   17:  aload_0
   18:  getfield    #6; //Field x:I
   21:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   24:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   27:  putfield    #9; //Field literal:Ljava/lang/String;
   30:  aload_0
   31:  new #2; //class java/lang/StringBuilder
   34:  dup
   35:  invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   38:  ldc #4; //String Value is
   40:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:  aload_0
   44:  getfield    #6; //Field x:I
   47:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   50:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   53:  putfield    #10; //Field builder:Ljava/lang/String;
   56:  return

}

Linie numerowane 5 - 27 są dla łańcuch o nazwie "literal"

Linie numerowane 31-53 są dla Ciągu o nazwie "builder"

Nie ma żadnej różnicy, dokładnie ten sam kod jest wykonywany dla obu łańcuchów.

 9
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 16:47:34
----------------------------------------------------------------------------------
                  String                    StringBuffer         StringBuilder
----------------------------------------------------------------------------------                 
Storage Area | Constant String Pool         Heap                   Heap 
Modifiable   |  No (immutable)              Yes( mutable )         Yes( mutable )
Thread Safe  |      Yes                     Yes                     No
 Performance |     Fast                 Very slow                  Fast
----------------------------------------------------------------------------------
 5
Author: Abhijit Maity,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-26 13:50:41

Rodzina Strun

String

The String class reprezentuje ciągi znaków. Wszystkie literały znaków w programie Java, takie jak "abc" są implementowane jako instancje tej klasy.

Obiekty String są niezmienne po ich utworzeniu nie możemy ich zmienić. (ciągi są stałymi )

  • Jeśli Łańcuch znaków jest tworzony za pomocą konstruktora lub metody, to łańcuchy te będą przechowywane w pamięć sterty jak również SringConstantPool. Ale przed zapisaniem w Puli wywołuje intern() metoda sprawdzania dostępności obiektów z tą samą zawartością w puli przy użyciu metody equals. jeśli String-copy jest dostępny w Puli, to zwraca referencję. W przeciwnym razie obiekt String jest dodawany do puli i zwraca referencję.

    • język Java zapewnia specjalne Wsparcie dla operatora concatenation string (+) oraz dla konwersji innych obiektów za sznurki. String concatenation jest zaimplementowany za pomocą klasy StringBuilder(lub StringBuffer) i jej metody append.

    String heapSCP = new String("Yash");
    heapSCP.concat(".");
    heapSCP = heapSCP + "M";
    heapSCP = heapSCP + 777;
    
    // For Example: String Source Code 
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
    
  • Literały łańcuchów są przechowywane w StringConstantPool.

    String onlyPool = "Yash";
    

StringBuffer i StringBuffer są zmiennymi sekwencjami znaków. Oznacza to, że można zmienić wartość tego obiektu. StringBuffer ma te same metody co StringBuilder, ale każda metoda w Stringbufferze jest zsynchronizowany, więc jest bezpieczny dla wątku.

  • Dane StringBuffer i StringBuilder mogą być tworzone tylko przy użyciu nowego operatora. Są więc przechowywane w pamięci sterty.

  • instancje StringBuilder nie są bezpieczne dla wielu wątków. Jeśli taka synchronizacja jest wymagana, zaleca się użycie StringBuffer.

    StringBuffer threadSafe = new StringBuffer("Yash");
    threadSafe.append(".M");
    threadSafe.toString();
    
    StringBuilder nonSync = new StringBuilder("Yash");
    nonSync.append(".M");
    nonSync.toString();
    
  • StringBuffer i StringBuilder mają specjalne metody, takie jak., replace(int start, int end, String str) i reverse().

    Uwaga : StringBuffer i SringBuilder są mutowalne, ponieważ zapewniają implementację Appendable Interface.


Kiedy użyć którego.

  • Jeśli a nie zmienisz wartości za każdym razem, lepiej jest użyć String Class. Jako część generyków jeśli chcesz posortować Comparable<T> lub porównaj wartości, a następnie wybierz String Class.

    //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
    Set<StringBuffer> set = new TreeSet<StringBuffer>();
    set.add( threadSafe );
    System.out.println("Set : "+ set);
    
  • Jeśli zamierzasz modyfikować wartość za każdym razem idź do StringBuilder, który jest szybszy niż StringBuffer. Jeśli wiele wątków modyfikuje wartość, przejdź do StringBuffer.

 5
Author: Yash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-24 05:59:36

Również {[0] } jest bezpieczne dla wątków, które StringBuilder nie są.

Więc w sytuacji w czasie rzeczywistym, gdy różne wątki mają do niego dostęp, StringBuilder może mieć nieokreślony wynik.

 3
Author: Lars Andren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 03:32:42

Zauważ, że jeśli używasz Javy 5 lub nowszej, powinieneś użyć StringBuilder zamiast StringBuffer. Z dokumentacji API:

Od wydania JDK 5, klasa ta została uzupełniona o równoważną klasę przeznaczoną do użytku przez pojedynczy wątek, StringBuilder. Klasa StringBuilder powinna być zazwyczaj używana zamiast tej, ponieważ obsługuje wszystkie te same operacje, ale jest szybsza, ponieważ nie wykonuje żadnej synchronizacji.

W praktyce prawie nigdy nie użyjesz tego z wielu wątki w tym samym czasie, więc synchronizacja StringBuffer jest prawie zawsze niepotrzebna.

 3
Author: Jesper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 08:11:37

Osobiście uważam, że nie ma żadnego zastosowania w świecie rzeczywistym dla StringBuffer. Czy kiedykolwiek chciałbym komunikować się między wieloma wątkami, manipulując sekwencją znaków? To wcale nie brzmi użytecznie, ale może jeszcze nie ujrzałem światła:)

 3
Author: fredoverflow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-06 09:46:37

Różnica między String a pozostałymi dwoma klasami polega na tym, że String jest niezmienny, a pozostałe dwie są zmiennymi klasami.

Ale dlaczego mamy dwie klasy w tym samym celu?

Powodem jest to, że {[0] } jest bezpieczne, a StringBuilder nie jest. StringBuilder jest nową klasą na StringBuffer Api i została wprowadzona w JDK5 i jest zawsze zalecana, jeśli pracujesz w środowisku z pojedynczym wątkiem, ponieważ jest dużo Faster

Szczegółowe informacje można przeczytać http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/

 3
Author: Hitesh Garg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-05 02:45:14

W Javie, String jest niezmienny. Będąc niezmiennym mamy na myśli, że po utworzeniu ciągu znaków nie możemy zmienić jego wartości. StringBuffer jest zmienny. Po utworzeniu obiektu StringBuffer, po prostu dodajemy zawartość do wartości obiektu zamiast tworzyć nowy obiekt. StringBuilder jest podobny do StringBuffer, ale nie jest bezpieczny dla wątków. Metody Stingbuildera nie są zsynchronizowane, ale w porównaniu do innych ciągów, Stringbuilder działa najszybciej. Możesz się nauczyć różnica pomiędzy String, StringBuilder i StringBuffer poprzez ich implementację.

 2
Author: rajat ghai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-11 20:45:26