Różnica zmienności:
String
jest niezmienna , jeśli starają się zmieniać swoje wartości, inny obiekt zostanie utworzony, natomiast StringBuffer
i StringBuilder
są zmienne , aby mogli zmienić ich wartości.
Różnica w zabezpieczeniu gwintu:
Różnica między StringBuffer
i StringBuilder
jest StringBuffer
bezpieczna dla wątków. Więc jeśli aplikacja musi być uruchomiona tylko w jednym wątku, lepiej jest użyć StringBuilder
. StringBuilder
jest bardziej wydajny niż StringBuffer
.
Sytuacje:
- Jeśli łańcuch nie ma się zmienić, użyj klasy String, ponieważ
String
obiekt jest niezmienny.
- Jeśli łańcuch może się zmienić (na przykład: dużo logiki i operacji w konstrukcji łańcucha) i będzie można uzyskać do niego dostęp tylko z jednego wątku, użycie parametru
StringBuilder
jest wystarczające.
- Jeśli ciąg może się zmienić i będzie dostępny z wielu wątków, użyj parametru
StringBuffer
ponieważ StringBuffer
jest synchroniczne, aby zapewnić bezpieczeństwo wątków.
Strings
kiedy zmienić wartość tworzona jest kolejnym celem. Czy stare odwołanie do obiektu jest unieważniane, tak aby mogło być śmieciami gromadzonymi przez,GC
czy może nawet śmieciami?String
zStringBuilder
?String
gdy niezmienna struktura jest odpowiednia; uzyskanie nowej sekwencji znaków z aString
może pociągać za sobą niedopuszczalne obniżenie wydajności, zarówno w czasie pracy procesora, jak i pamięci (uzyskiwanie podciągów jest wydajne procesorowo, ponieważ dane nie są kopiowane, ale oznacza to, że potencjalnie znacznie większa ilość danych może pozostać przydzielona).StringBuilder
gdy chcesz utworzyć zmienną sekwencję znaków, zwykle do połączenia kilku sekwencji znaków razem.StringBuffer
w tych samych okolicznościach, których używałbyśStringBuilder
, ale gdy zmiany w łańcuchu bazowym muszą być zsynchronizowane (ponieważ kilka wątków odczytuje / modyfikuje bufor łańcucha).Zobacz przykład tutaj .
źródło
Podstawy:
String
to niezmienna klasa, której nie można zmienić.StringBuilder
to zmienna klasa, do której można dołączać, zamieniać lub usuwać znaki i ostatecznie przekonwertować na aString
StringBuffer
jest oryginalną zsynchronizowaną wersjąStringBuilder
Powinieneś preferować
StringBuilder
we wszystkich przypadkach, w których tylko jeden wątek uzyskuje dostęp do obiektu.Szczegóły:
Zauważ też, że
StringBuilder/Buffers
to nie magia, po prostu używają Array jako obiektu wspierającego i że Array musi zostać ponownie przydzielony, kiedy tylko się zapełni. Upewnij się i stwórz swojeStringBuilder/Buffer
obiekty wystarczająco duże, aby nie musiały być ciągle zmieniane przy każdym.append()
wywołaniu.Zmiana rozmiaru może stać się bardzo zdegenerowana. Zasadniczo zmienia rozmiar macierzy podkładu na 2-krotność jego obecnej wielkości za każdym razem, gdy trzeba ją rozszerzyć. Może to spowodować przydzielenie dużej ilości pamięci RAM i niewykorzystanie jej, gdy
StringBuilder/Buffer
klasy zaczną się powiększać.W Javie
String x = "A" + "B";
stosuje sięStringBuilder
za kulisami. W prostych przypadkach nie ma korzyści z deklarowania własnego. Ale jeśliString
budujesz duże obiekty, powiedzmy mniej niż 4k, to deklarowanieStringBuilder sb = StringBuilder(4096);
jest znacznie wydajniejsze niż konkatenacja lub użycie domyślnego konstruktora, który ma tylko 16 znaków. Jeśli maszString
mniej niż 10k, zainicjuj go konstruktorem na 10k, aby być bezpiecznym. Ale jeśli zostanie zainicjowany do 10k, to napiszesz 1 znak więcej niż 10k, zostanie on ponownie przydzielony i skopiowany do tablicy 20k. Tak więc inicjowanie wysokiego jest lepsze niż niskie.W przypadku automatycznej zmiany rozmiaru przy 17. znaku macierz zastępcza zostaje ponownie przydzielona i skopiowana do 32 znaków, przy 33 znaku to się dzieje ponownie i można ponownie przydzielić i skopiować tablicę na 64 znaki. Możesz zobaczyć, jak to się degeneruje do wielu ponownych alokacji i kopii, których tak naprawdę starasz się unikać
StringBuilder/Buffer
.Pochodzi z kodu źródłowego JDK 6 dla AbstractStringBuilder
Najlepszą praktyką jest zainicjowanie
StringBuilder/Buffer
nieco większego, niż myślisz, że będziesz potrzebować, jeśli nie wiesz od razu, jak dużyString
będzie, ale możesz się domyślić. Jeden przydział nieco więcej pamięci niż potrzebujesz będzie lepszy niż wiele ponownych przydziałów i kopii.Uważaj również na zainicjowanie znaku
StringBuilder/Buffer
a,String
ponieważ przydzieli tylko rozmiar ciągu + 16 znaków, co w większości przypadków po prostu rozpocznie zdegenerowaną ponowną alokację i cykl kopiowania, którego próbujesz uniknąć. Poniższy kod pochodzi bezpośrednio z kodu źródłowego Java 6.Jeśli przypadkiem trafisz na instancję
StringBuilder/Buffer
, której nie utworzyłeś i nie możesz kontrolować wywoływanego konstruktora, istnieje sposób na uniknięcie zdegenerowanego ponownego przydzielania i kopiowania. Zadzwoń.ensureCapacity()
z rozmiarem, w którym chcesz sięString
dopasować.Alternatywy:
Dla przypomnienia, jeśli robisz naprawdę ciężkie
String
budowanie i manipulowanie, istnieje o wiele bardziej zorientowana na wydajność alternatywa zwana Liny .Inną alternatywą jest utworzenie
StringList
implementacji poprzez podklasęArrayList<String>
i dodanie liczników do śledzenia liczby znaków na każdej.append()
i wszystkich operacjach mutacji na liście, a następnie przesłonięcie,.toString()
aby utworzyćStringBuilder
dokładnie taki rozmiar, jakiego potrzebujesz i zapętlić listę i budować wyjściowy, możesz nawet uczynić tęStringBuilder
instancję zmienną i „buforować” wyniki.toString()
i tylko ponownie ją wygenerować, gdy coś się zmieni.Nie zapominaj również o
String.format()
budowaniu stałych sformatowanych danych wyjściowych, które mogą być zoptymalizowane przez kompilator, ponieważ są lepsze.źródło
String x = "A" + "B";
naprawdę kompiluje się, aby być StringBuilder? Dlaczego nie miałby po prostu się skompilowaćString x = "AB";
, powinien używać StringBuilder tylko wtedy, gdy składniki nie są znane w czasie kompilacji.Masz na myśli konkatenację?
Przykład ze świata rzeczywistego: chcesz utworzyć nowy ciąg z wielu innych .
Na przykład, aby wysłać wiadomość:
Strunowy
StringBuilder
Lub
StringBuffer (składnia jest dokładnie taka sama jak w StringBuilder, efekty różnią się)
O
StringBuffer
vs.StringBuilder
Pierwsza jest zsynchronizowana, a później nie.
Tak więc, jeśli wywołasz ją kilka razy w jednym wątku (co stanowi 90% przypadków),
StringBuilder
będzie działać znacznie szybciej, ponieważ nie przestanie sprawdzać, czy jest właścicielem blokady wątku.Dlatego zaleca się stosowanie
StringBuilder
(chyba że masz więcej niż jeden wątek uzyskujący dostęp do niego w tym samym czasie, co jest rzadkie)String
konkatenacja ( przy użyciu operatora + ) może być zoptymalizowana przez kompilator do użyciaStringBuilder
pod spodem, więc nie trzeba się już martwić, w dawnych czasach Java było to coś, o czym wszyscy mówią, że należy unikać za wszelką cenę, ponieważ każdą konkatenację utworzył nowy obiekt String. Współczesne kompilatory już tego nie robią, ale nadal dobrą praktyką jest używanie ichStringBuilder
na wypadek, gdybyś używał „starego” kompilatora.edytować
Dla kogo ciekawi, to właśnie robi kompilator dla tej klasy:
javap -c StringConcatenation
Linie ponumerowane 5–27 dotyczą ciągu o nazwie „dosłowny”
Linie o numerach 31–53 dotyczą ciągu o nazwie „konstruktor”
Nie ma różnicy, dokładnie ten sam kod jest wykonywany dla obu łańcuchów.
źródło
StringBuilder
konkatenacji ciągów po prawej stronie zadania. Każda dobra implementacja użyje StringBuilder za kulisami, jak mówisz. Co więcej, twój przykład"a" + "b"
zostałby skompilowany w jeden literał,"ab"
ale jeśli go użyjeszStringBuilder
, spowoduje to dwa niepotrzebne wywołaniaappend()
."a"+"b"
ale żeby powiedzieć, co było połączeniem String , zmieniam to, aby było jawne. Nie mówisz, dlaczego nie jest dobrą praktyką. Właśnie to robi (nowoczesny) kompilator. @fuzzy, zgadzam się, zwłaszcza gdy wiesz, jaki byłby końcowy rozmiar łańcucha (w przybliżeniu).źródło
synchronised
i dlatego .Strunowy
String class
Reprezentuje ciągi znaków. Wszystkie literały łańcuchowe w programie Java, takie jak"abc"
zaimplementowane jako instancje tej klasy.Obiekty łańcuchowe są niezmienne po ich utworzeniu, którego nie możemy zmienić. ( Ciągi są stałymi )
Jeśli ciąg jest tworzony za pomocą konstruktora lub metody to te ciągi będą przechowywane w pamięci sterty , jak również
SringConstantPool
. Ale przed zapisaniem w puli wywołujeintern()
metodę sprawdzania dostępności obiektu o tej samej zawartości w puli przy użyciu metody równości. Jeśli kopia ciągów jest dostępna w puli, zwraca odwołanie. W przeciwnym razie obiekt String zostanie dodany do puli i zwróci odwołanie.+
) oraz konwersji innych obiektów na ciągi. Łączenie ciągów jest realizowane za pośrednictwem klasy StringBuilder (lub StringBuffer) i jej metody dołączania.Literały łańcuchowe są przechowywane w
StringConstantPool
.StringBuilder i StringBuffer to zmienna sekwencja znaków. Oznacza to, że można zmienić wartość tych obiektów. StringBuffer ma te same metody co StringBuilder, ale każda metoda w StringBuffer jest zsynchronizowana, więc jest bezpieczna dla wątków.
Dane StringBuffer i StringBuilder można tworzyć 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 i StringBuilder wywierają metod specjalnych, takich jak.,
replace(int start, int end, String str)
Ireverse()
.Kiedy stosować który.
Jeśli nie zamierzasz zmieniać wartości za każdym razem, lepiej użyć
String Class
. W ramach Generics, jeśli chcesz posortowaćComparable<T>
lub porównać wartości, przejdź doString Class
.Jeśli zamierzasz modyfikować wartość za każdym razem, gdy korzystasz z StringBuilder, który jest szybszy niż StringBuffer. Jeśli wiele wątków modyfikuje wartość, przejdź do StringBuffer.
źródło
Ponadto
StringBuffer
jest bezpieczny dla wątków, coStringBuilder
nie jest.Tak więc w sytuacji czasu rzeczywistego, gdy różne wątki uzyskują do niego dostęp,
StringBuilder
może mieć nieokreślony skutek.źródło
Pamiętaj, że jeśli używasz Java 5 lub nowszej, powinieneś użyć
StringBuilder
zamiastStringBuffer
. Z dokumentacji API:W praktyce prawie nigdy nie użyjesz tego z wielu wątków jednocześnie, więc synchronizacja,
StringBuffer
która to robi, prawie zawsze jest niepotrzebnym narzutem.źródło
Osobiście nie sądzę, aby można było z tego skorzystać w prawdziwym świecie
StringBuffer
. Kiedy miałbym kiedykolwiek chcieć komunikować się między wieloma wątkami, manipulując sekwencją znaków? To wcale nie brzmi pożytecznie, ale może jeszcze nie widzę światła :)źródło
Różnica między String a pozostałymi dwiema klasami polega na tym, że String jest niezmienny, a pozostałe dwie klasy są zmiennymi.
Ale dlaczego mamy dwie klasy do tego samego celu?
Powodem jest to, że
StringBuffer
wątek jest bezpieczny iStringBuilder
nie jest.StringBuilder
jest nową klasąStringBuffer Api
i został wprowadzonyJDK5
i jest zawsze zalecany, jeśli pracujesz w środowisku jednowątkowym, ponieważ jest go dużoFaster
Aby uzyskać szczegółowe informacje, przeczytaj http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
źródło
W języku Java ciąg jest niezmienny. Będąc niezmiennymi, mamy na myśli, że po utworzeniu Łańcucha nie możemy zmienić jego wartości. StringBuffer można modyfikować. Po utworzeniu obiektu StringBuffer po prostu dołączamy treść do wartości obiektu, zamiast tworzyć nowy obiekt. StringBuilder jest podobny do StringBuffer, ale nie jest bezpieczny dla wątków. Metody StingBuilder nie są zsynchronizowane, ale w porównaniu do innych Ciągów, Konstruktor Ciągów działa najszybciej. Różnicę między String, StringBuilder i StringBuffer można poznać , implementując je.
źródło