Różnica między StringBuilder i StringBuffer


1577

Jaka jest główna różnica między StringBufferi StringBuilder? Czy przy podejmowaniu decyzji dotyczącej któregokolwiek z nich występują problemy z wydajnością?

Odpowiedzi:


1665

StringBufferjest zsynchronizowany, StringBuildernie jest.


239
a StringBuilder ma zastąpić StringBuffer, w którym synchronizacja nie jest wymagana
Joel

95
a synchronizacja praktycznie nigdy nie jest wymagana. Jeśli ktoś chce synchronizować na StringBuilder, może po prostu otoczyć cały blok kodu zsynchronizowanym (sb) {} w instancji
locka 24.04.13

23
@locka Twierdziłbym, że StringBuffer nigdy nie jest dobrym pomysłem (chyba że masz API, które tego wymaga) vanillajava.blogspot.de/2013/04/…
Peter Lawrey

8
Jedyne miejsce, w którym widzę StringBuffer, to dane wyjściowe podobne do konsoli i różne narzędzia do rejestrowania: wiele wątków może generować konflikt. Ponieważ nie chcesz, aby 2 dane wyjściowe się pomieszały ... ale zwykle synchronizacja na poziomie StringBuffer jest zbyt niska, będziesz chciał zsynchronizować się z aplikacją taką jak levelm, więc odpowiedź locka jest najlepsza i StringBuffer powinien być przestarzały. Oszczędziłoby to czas przeglądu kodu dla początkujących.
Remi Morin

20
Dobry mnemonik dla tych, którzy mieszają te dwa - BuFFer był pierwszy, starszy i dlatego zsynchronizowany. Nowsza klasa Builder używa wzorca Builder i jest asynchroniczna.
Datageek

728

StringBuilderjest szybszy niż StringBufferdlatego, że nie jest synchronized.

Oto prosty test porównawczy:

public class Main {
    public static void main(String[] args) {
        int N = 77777777;
        long t;

        {
            StringBuffer sb = new StringBuffer();
            t = System.currentTimeMillis();
            for (int i = N; i --> 0 ;) {
                sb.append("");
            }
            System.out.println(System.currentTimeMillis() - t);
        }

        {
            StringBuilder sb = new StringBuilder();
            t = System.currentTimeMillis();
            for (int i = N; i > 0 ; i--) {
                sb.append("");
            }
            System.out.println(System.currentTimeMillis() - t);
        }
    }
}

Test nie daje numery 2241 msdla StringBuffervs 753 msdla StringBuilder.


10
Zmieniłem literał ciąg na coś większego: „szybki brązowy lis” i uzyskałem ciekawsze wyniki. Zasadniczo są one tak szybkie. Właściwie zabrakło mi pamięci, więc musiałem usunąć kilka siódemek. Objaśnienie: synchronizacja jest optymalizowana przez hotspot. Zasadniczo mierzysz czas, jaki zajmuje hotspot (i prawdopodobnie kilka innych optymalizacji).
Jilles van Gurp

7
Musisz się wcześniej rozgrzać. Ten test jest niesprawiedliwy wobec StringBuffer. Byłoby również dobrze, gdyby rzeczywiście coś do niego dodało. Właściwie przerzuciłem test, dołączyłem losowy ciąg i dostałem test odwrotny. Mówi się, że nie można ufać prostym testom porównawczym. Przeciwnie pokazuje, że StringBuffer jest szybszy. 5164 dla StringBuilder vs 3699 dla StringBuffer hastebin.com/piwicifami.avrasm
mmm

75
Po raz pierwszy widzę --> 0w pętli. Chwilę zajęło mi zrozumienie, co to znaczy. Czy jest to coś, co faktycznie jest używane w praktyce zamiast zwykłej ...; i > 0; i--składni?
Raimund Krämer,

19
Że i --> jest naprawdę denerwujące pod względem składni ... Na początku myślałem, że to strzała z powodu komentarzy na temat sztuki ASCII.
Sameer Puri,

14
Inne kończą się różnymi wynikami: alblue.bandlem.com/2016/04/jmh-stringbuffer-stringbuilder.html . Testy porównawcze powinny być naprawdę wykonywane przy użyciu JMH, a nie za pomocą prostego. main()Ponadto test porównawczy jest niesprawiedliwy. Nie ma rozgrzewki.
Lukas Eder

249

Zasadniczo StringBuffermetody są synchronizowane podczasStringBuilder nie są.

Operacje są „prawie” takie same, ale stosowanie metod zsynchronizowanych w jednym wątku to przesada.

To właściwie tyle.

Cytat z StringBuilder API :

Ta klasa [StringBuilder] zapewnia API kompatybilne z StringBuffer, ale bez gwarancji synchronizacji . Ta klasa została zaprojektowana do użycia jako zastępczy element zastępujący StringBuffer w miejscach, w których bufor łańcucha był używany przez pojedynczy wątek (jak to zwykle ma miejsce). Tam, gdzie to możliwe, zaleca się stosowanie tej klasy zamiast StringBuffer, ponieważ w większości implementacji będzie ona szybsza.

Więc został stworzony, aby go zastąpić.

To samo stało się z Vectori ArrayList.


1
Również z Hashtablei HashMap.
shmosel

176

Ale czy chcesz uzyskać wyraźną różnicę za pomocą przykładu?

StringBuffer lub StringBuilder

Po prostu użyj, StringBuilderchyba że naprawdę próbujesz współdzielić bufor między wątkami. StringBuilderjest niezsynchronizowanym (mniej narzutu = bardziej wydajnym) młodszym bratem oryginalnej synchronizowanej StringBufferklasy.

StringBufferbył pierwszy. Firma Sun martwiła się o poprawność w każdych warunkach, dlatego zsynchronizowała ją, aby na wszelki wypadek była bezpieczna dla wątków.

StringBuilderprzyszedł później. Większość zastosowańStringBuffer była jednowątkowa i niepotrzebnie pokrywała koszty synchronizacji.

Ponieważ StringBuilderjest zastępczym zamiennikiem dlaStringBuffer bez synchronizacji, nie byłoby żadnych różnic pomiędzy przykładami.

Jeśli próby akcję pomiędzy wątkami, można użyć StringBuffer, ale zastanowić się, czy synchronizacja wyższego poziomu jest konieczne, na przykład może zamiast używać StringBuffer, należy zsynchronizować metody, które wykorzystują StringBuilder.


14
Pierwsza dobra odpowiedź !! Chodzi o to, „chyba że dzielisz bufor między wątkami”
AlexWien,

1
bardzo szczegółowa odpowiedź!
Raúl

81

Najpierw zobaczmy podobieństwa : zarówno StringBuilder, jak i StringBuffer można modyfikować. Oznacza to, że możesz zmienić ich zawartość w tej samej lokalizacji.

Różnice : StringBuffer można również modyfikować i synchronizować. Gdzie jako StringBuilder jest zmienny, ale domyślnie nie jest synchronizowany.

Znaczenie synchronizacji (synchronizacja) : Gdy coś jest synchronizowane, wiele wątków może uzyskać dostęp i modyfikować je bez żadnego problemu lub efektu ubocznego. StringBuffer jest zsynchronizowany, więc możesz używać go z wieloma wątkami bez żadnego problemu.

Którego użyć, kiedy? StringBuilder: Gdy potrzebujesz łańcucha, który można modyfikować, a tylko jeden wątek uzyskuje do niego dostęp i go modyfikuje. StringBuffer: Gdy potrzebujesz łańcucha, który można modyfikować, a wiele wątków ma do niego dostęp i go modyfikuje.

Uwaga : Nie używaj StringBuffer niepotrzebnie, tzn. Nie używaj go, jeśli tylko jeden wątek modyfikuje i uzyskuje do niego dostęp, ponieważ ma dużo kodu blokującego i odblokowującego do synchronizacji, który niepotrzebnie zajmuje czas procesora. Nie używaj zamków, chyba że jest to wymagane.


2
Wystarczy wspomnieć, że wywołania metody INDYWIDUALNE StringBuffera są bezpieczne dla wątków. Ale jeśli masz wiele wierszy kodu, użyj zsynchronizowanego bloku kodu, aby zagwarantować bezpieczeństwo wątków, z pewną blokadą / monitorem (jak zwykle ...). Zasadniczo nie zakładaj tylko, że korzystanie z biblioteki wątków natychmiast gwarantuje bezpieczeństwo wątków w Twoim programie!
Kevin Lee

57

W pojedynczych wątkach StringBuffer nie jest znacznie wolniejszy niż StringBuilder , dzięki optymalizacji JVM. W wielowątkowości nie można bezpiecznie używać StringBuilder.

Oto mój test (nie test, tylko test):

public static void main(String[] args) {

    String withString ="";
    long t0 = System.currentTimeMillis();
    for (int i = 0 ; i < 100000; i++){
        withString+="some string";
    }
    System.out.println("strings:" + (System.currentTimeMillis() - t0));

    t0 = System.currentTimeMillis();
    StringBuffer buf = new StringBuffer();
    for (int i = 0 ; i < 100000; i++){
        buf.append("some string");
    }
    System.out.println("Buffers : "+(System.currentTimeMillis() - t0));

    t0 = System.currentTimeMillis();
    StringBuilder building = new StringBuilder();
    for (int i = 0 ; i < 100000; i++){
        building.append("some string");
    }
    System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}

Wyniki:
łańcuchy: 319740
Bufory: 23
Konstruktor: 7!

Tak więc Konstruktorzy są szybsi niż bufory i DZIŚ szybciej niż konkatenacja łańcuchów. Teraz użyjmy Executora dla wielu wątków:

public class StringsPerf {

    public static void main(String[] args) {

        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
        //With Buffer
        StringBuffer buffer = new StringBuffer();
        for (int i = 0 ; i < 10; i++){
            executorService.execute(new AppendableRunnable(buffer));
        }
        shutdownAndAwaitTermination(executorService);
        System.out.println(" Thread Buffer : "+ AppendableRunnable.time);

        //With Builder
        AppendableRunnable.time = 0;
        executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
        StringBuilder builder = new StringBuilder();
        for (int i = 0 ; i < 10; i++){
            executorService.execute(new AppendableRunnable(builder));
        }
        shutdownAndAwaitTermination(executorService);
        System.out.println(" Thread Builder: "+ AppendableRunnable.time);

    }

   static void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown(); // code reduced from Official Javadoc for Executors
        try {
            if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
                pool.shutdownNow();
                if (!pool.awaitTermination(60, TimeUnit.SECONDS))
                    System.err.println("Pool did not terminate");
            }
        } catch (Exception e) {}
    }
}

class AppendableRunnable<T extends Appendable> implements Runnable {

    static long time = 0;
    T appendable;
    public AppendableRunnable(T appendable){
        this.appendable = appendable;
    }

    @Override
    public void run(){
        long t0 = System.currentTimeMillis();
        for (int j = 0 ; j < 10000 ; j++){
            try {
                appendable.append("some string");
            } catch (IOException e) {}
        }
        time+=(System.currentTimeMillis() - t0);
    }
}

Teraz StringBuffers zajmuje 157 ms na 100000 dołączeń. To nie jest ten sam test, ale w porównaniu z poprzednimi 37 ms można bezpiecznie założyć, że dołączenia StringBuffers są wolniejsze przy użyciu wielowątkowości . Powodem jest to, że JIT / hotspot / kompilator / coś dokonuje optymalizacji, gdy wykryje, że nie ma potrzeby sprawdzania blokad.

Ale dzięki StringBuilder masz java.lang.ArrayIndexOutOfBoundsException , ponieważ współbieżny wątek próbuje dodać coś tam, gdzie nie powinno.

Wniosek jest taki, że nie musisz ścigać StringBuffers. A jeśli masz wątki, zastanów się, co robią, zanim spróbujesz uzyskać kilka nanosekund.


5
Zapomniałeś zrobić "t0 = System.currentTimeMillis ();" przed wykonaniem testu StringBuilder. Tak więc liczba wyświetlana dla StringBuilder jest w rzeczywistości czasem potrzebnym do uruchomienia testu bufora łańcuchowego ORAZ testu łańcucha znaków. Dodaj ten wiersz, a zobaczysz, że StringBuilder JEST szybszy o DWÓCH CZASACH.
Gena Batsyan,

Zauważ, że withString+="some string"+i+" ; ";nie jest to równoważne z pozostałymi dwiema pętlami i dlatego nie jest uczciwym porównaniem.
Dave Jarvis,

Dokładnie, poprawione. Ciągi myśli są wciąż bardzo wolne.
Nicolas Zozol

Czy możesz wyjaśnić więcej, dlaczego zgłoszenie
wyjątku

Powinieneś używać JMH do testów porównawczych. Twój test porównawczy jest naprawdę niedokładny.
Lukas Eder

42

StringBuilder został wprowadzony w Javie 1.5, więc nie będzie działał z wcześniejszymi JVM.

Z Javadocs :

Klasa StringBuilder zapewnia API kompatybilne z StringBuffer, ale bez gwarancji synchronizacji. Ta klasa została zaprojektowana do użycia jako zastępczy element zastępujący StringBuffer w miejscach, w których bufor łańcucha był używany przez pojedynczy wątek (jak to zwykle ma miejsce). Tam, gdzie to możliwe, zaleca się stosowanie tej klasy zamiast StringBuffer, ponieważ w większości implementacji będzie ona szybsza.


13
Koniec 1.4 okresu użytkowania, więc nie warto martwić się o wersję wcześniejszą niż 1.5.
Tom Hawtin - tackline

@ tomHawtin-tackline niekoniecznie - istnieją produkty dla przedsiębiorstw w wersji wcześniejszej niż 1.4, z których większość z nas korzysta codziennie. Również Java BlackBerry oparta jest na wersji 1.4 i wciąż jest bardzo aktualna.
Richard Le Mesurier

A CDC i CLDC nie mają StringBuilder.
Jin Kwon,

37

Całkiem dobre pytanie

Oto różnice, które zauważyłem:

StringBuffer: -

StringBuffer is  synchronized
StringBuffer is  thread-safe
StringBuffer is  slow (try to write a sample program and execute it, it will take more time than StringBuilder)

StringBuilder: -

 StringBuilder is not synchronized 
 StringBuilder is not thread-safe
 StringBuilder performance is better than StringBuffer.

Zwykła rzecz :-

Oba mają te same metody z tymi samymi podpisami. Oba są zmienne.


23

StringBuffer

  • Zsynchronizowany, dzięki temu wątkowo bezpieczny
  • Wątek bezpieczny, a zatem wolny

StringBuilder

  • Wprowadzono w Javie 5.0
  • Asynchroniczny, a zatem szybki i wydajny
  • Użytkownik wyraźnie musi go zsynchronizować, jeśli chce
  • Możesz go zastąpić StringBufferbez żadnych innych zmian

UWAGA: Tylko pojedyncze operacje są bezpieczne dla wątków, wiele operacji nie. np jeśli zadzwonić appenddwa razy, albo appendi toStringnie, nie jest bezpieczne.
Peter Lawrey,

22

StringBuilder nie jest bezpieczny dla wątków. Bufor ciągów to. Więcej informacji tutaj .

EDYCJA: Jeśli chodzi o wydajność, po uruchomieniu hotspotu StringBuilder jest zwycięzcą. Jednak w przypadku małych iteracji różnica wydajności jest znikoma.


21

StringBuilderi StringBuffersą prawie takie same. Różnica polega na tym, że nie StringBufferjest zsynchronizowana StringBuilder. Chociaż StringBuilderjest szybszy niż StringBuffer, różnica w wydajności jest bardzo mała. StringBuilderjest zamiennikiem SUN dla StringBuffer. Po prostu unika synchronizacji ze wszystkimi publicznymi metodami. Zamiast tego ich funkcjonalność jest taka sama.

Przykład dobrego użytkowania:

Jeśli twój tekst ma się zmienić i jest używany przez wiele wątków, lepiej użyć tego StringBuffer. Jeśli twój tekst ma się zmienić, ale jest używany przez jeden wątek, użyj StringBuilder.


19

StringBuffer

StringBuffer można modyfikować, co oznacza, że ​​można zmienić wartość obiektu. Obiekt utworzony za pomocą StringBuffer jest przechowywany w stercie. StringBuffer ma takie same metody jak StringBuilder, ale każda metoda w StringBuffer jest zsynchronizowana, a StringBuffer jest bezpieczny dla wątków.

z tego powodu nie pozwala dwóm wątkom na jednoczesny dostęp do tej samej metody. Dostęp do każdej metody może mieć jeden wątek na raz.

Ale bycie bezpiecznym dla wątków ma również wady, ponieważ wydajność uderzeń StringBuffer wynika z właściwości bezpiecznych dla wątków. Zatem StringBuilder jest szybszy niż StringBuffer podczas wywoływania tych samych metod dla każdej klasy.

Wartość StringBuffer można zmienić, co oznacza, że ​​można ją przypisać do nowej wartości. W dzisiejszych czasach jest to najczęściej zadawane pytanie dotyczące wywiadu, różnice między powyższymi klasami. Bufor ciągów można przekonwertować na ciąg przy użyciu metody toString ().

StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .

demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer

StringBuilder

StringBuilder jest taki sam jak StringBuffer, tzn. Przechowuje obiekt w stercie i można go również modyfikować. Główną różnicą między StringBuffer i StringBuilder jest to, że StringBuilder również nie jest bezpieczny dla wątków. StringBuilder jest szybki, ponieważ nie jest bezpieczny dla wątków.

StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified

demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder

wprowadź opis zdjęcia tutaj

Zasób: String Vs StringBuffer Vs StringBuilder


StringBuilder jest niezmienny, a typ String jest zmienny
Brinda Rathod

Nie zgodziłbym się, że Strings i StringBuilders są „szybkie”, a StringBuffers są „bardzo wolne”. Zobacz powyższe odpowiedzi.
FireCubez

17

String jest niezmienny.

StringBuffer jest zmienny i zsynchronizowany.

StringBuilder jest również zmienny, ale nie jest zsynchronizowany.


Dodatkowo StringBuffer blokuje wątki w celu uzyskania dostępu do danych bezpiecznych dla wątku, dlatego operacja przebiega powoli. StringBuilder nie blokuje wątku i działa w sposób wielowątkowy, dlatego jest szybki. Łańcuch - gdy nie trzeba łączyć łańcucha, jest to dobry sposób, ale gdy jest potrzebny, należy użyć StringBuilder -> ponieważ String tworzy za każdym razem nowy obiekt w stercie, ale StringBuilder zwraca ten sam obiekt ...
Musa

11

Javadoc wyjaśnia różnicę:

Ta klasa zapewnia API kompatybilne z StringBuffer, ale bez gwarancji synchronizacji. Ta klasa została zaprojektowana do użycia jako zastępczy element zastępujący StringBuffer w miejscach, w których bufor łańcucha był używany przez pojedynczy wątek (jak to zwykle ma miejsce). Tam, gdzie to możliwe, zaleca się stosowanie tej klasy zamiast StringBuffer, ponieważ w większości implementacji będzie ona szybsza.


10

StringBuilder (wprowadzony w Javie 5) jest identyczny z StringBuffer , ale jego metody nie są zsynchronizowane. Oznacza to, że ma lepszą wydajność niż ta ostatnia, ale wadą jest to, że nie jest bezpieczna dla wątków.

Przeczytaj samouczek, aby uzyskać więcej informacji.


6

Prosty program ilustrujący różnicę między StringBuffer a StringBuilder:

/**
 * Run this program a couple of times. We see that the StringBuilder does not
 * give us reliable results because its methods are not thread-safe as compared
 * to StringBuffer.
 * 
 * For example, the single append in StringBuffer is thread-safe, i.e.
 * only one thread can call append() at any time and would finish writing
 * back to memory one at a time. In contrast, the append() in the StringBuilder 
 * class can be called concurrently by many threads, so the final size of the 
 * StringBuilder is sometimes less than expected.
 * 
 */
public class StringBufferVSStringBuilder {

    public static void main(String[] args) throws InterruptedException {

        int n = 10; 

        //*************************String Builder Test*******************************//
        StringBuilder sb = new StringBuilder();
        StringBuilderTest[] builderThreads = new StringBuilderTest[n];
        for (int i = 0; i < n; i++) {
            builderThreads[i] = new StringBuilderTest(sb);
        }
        for (int i = 0; i < n; i++) {
            builderThreads[i].start();
        }
        for (int i = 0; i < n; i++) {
            builderThreads[i].join();
        }
        System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());

        //*************************String Buffer Test*******************************//

        StringBuffer sb2 = new StringBuffer();
        StringBufferTest[] bufferThreads = new StringBufferTest[n];
        for (int i = 0; i < n; i++) {
            bufferThreads[i] = new StringBufferTest(sb2);
        }
        for (int i = 0; i < n; i++) {
            bufferThreads[i].start();
        }
        for (int i = 0; i < n; i++) {
            bufferThreads[i].join();
        }
        System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());

    }

}

// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {

    StringBuilder sb;

    public StringBuilderTest (StringBuilder sb) {
        this.sb = sb;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            sb.append("A");
        }

    }
}


//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {

    StringBuffer sb2;

    public StringBufferTest (StringBuffer sb2) {
        this.sb2 = sb2;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            sb2.append("A");
        }

    }
}

4

StringBuffer służy do przechowywania ciągów znaków, które zostaną zmienione (obiektów String nie można zmienić). Automatycznie rozszerza się w razie potrzeby. Powiązane klasy: String, CharSequence.

StringBuilder został dodany w Javie 5. Jest pod każdym względem identyczny z StringBuffer, z wyjątkiem tego, że nie jest zsynchronizowany, co oznacza, że ​​jeśli wiele wątków uzyskuje dostęp do niego w tym samym czasie, mogą wystąpić problemy. W przypadku programów jednowątkowych najczęstszy przypadek, unikając narzutu związanego z synchronizacją, powoduje, że StringBuilder jest nieco szybszy.


4
Programy jednowątkowe nie są najczęstszym przypadkiem w Javie, ale StringBuilderzwykle są lokalne dla metody, w której są widoczne tylko dla jednego wątku.
finnw

4

StringBufferjest zsynchronizowany, ale StringBuildernie jest. W rezultacie StringBuilderjest szybszy niż StringBuffer.


4

StringBuffer można modyfikować. Może się zmieniać pod względem długości i zawartości. StringBuffer są bezpieczne dla wątków, co oznacza, że ​​mają zsynchronizowane metody kontroli dostępu, dzięki czemu tylko jeden wątek może uzyskać dostęp do zsynchronizowanego kodu obiektu StringBuffer na raz. Tak więc obiektów StringBuffer można ogólnie bezpiecznie używać w środowisku wielowątkowym, w którym wiele wątków może próbować uzyskać dostęp do tego samego obiektu StringBuffer w tym samym czasie.

StringBuilder Klasa StringBuilder jest bardzo podobna do StringBuffer, z tym wyjątkiem, że jej dostęp nie jest zsynchronizowany, więc nie jest bezpieczny wątkowo. Bez synchronizacji wydajność StringBuilder może być lepsza niż StringBuffer. Dlatego jeśli pracujesz w środowisku jednowątkowym, użycie StringBuilder zamiast StringBuffer może spowodować zwiększenie wydajności. Dotyczy to również innych sytuacji, takich jak zmienna lokalna StringBuilder (tj. Zmienna w metodzie), w której tylko jeden wątek będzie uzyskiwał dostęp do obiektu StringBuilder.


4

StringBuffer:

  • Wielowątkowy
  • Zsynchronizowane
  • Wolny niż StringBuilder

StringBuilder

  • Jednowątkowy
  • Niezsynchronizowane
  • Szybszy niż kiedykolwiek String

2
Dokładniej, String c = a + bjest równoważne String c = new StringBuilder().append(a).append(b).toString(), więc nie jest szybsze. Tyle tylko, że tworzysz nowy dla każdego przypisania łańcucha, podczas gdy możesz mieć tylko jedno ( String d = a + b; d = d + c;to String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();jednocześnie StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();uratuje jedno instancje StringBuilder).
Chop

4

Konstruktor ciągów :

int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.

Bufor ciągów

StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);  

Zaleca się używanie StringBuilder, gdy tylko jest to możliwe, ponieważ jest szybszy niż StringBuffer. Jeśli jednak bezpieczeństwo wątków jest konieczne, najlepszą opcją są obiekty StringBuffer.


Jeśli potrzebujesz bezpieczeństwa wątków, najlepszą opcją jest użycie StringBuilder, ponieważ StringBuffer jest bezpieczny tylko dla poszczególnych operacji. W przypadku wielu operacji potrzebujesz jawnego blokowania.
Peter Lawrey,

4

Lepsze użycie, StringBuilderponieważ nie jest zsynchronizowane i dlatego zapewnia lepszą wydajność. StringBuilderjest drop-in zamiennikiem starszych StringBuffer.


3
@Zaznacz prawda, ale przez większość czasu StringBu(ff|ild)erjest to zmienna lokalna używana tylko przez pojedynczy wątek.
gabuzo

1
@MarkMcKenna: Nawet w aplikacjach wielowątkowych często trzeba albo użyć zewnętrznego blokowania, albo wykonać dodatkową pracę, aby tego uniknąć. Na przykład, jeśli dwa wątki chcą dołączyć rekord zawierający wiele ciągów do konstruktora ciągów, musiałyby agregować dane, które mają zostać dodane, a następnie dodać je jako jednostkę, nawet jeśli byłoby to szybsze - brak problemów z wątkami - po prostu wykonać sekwencję dyskretnych operacji dołączania.
supercat

3

Ponieważ StringBufferjest zsynchronizowany, wymaga dodatkowego wysiłku, dlatego opiera się na perforamance, jest nieco wolniejszy niż StringBuilder.


3

Nie ma żadnych różnic między podstawowymi StringBuilderi StringBufferistnieją tylko kilka różnic między nimi. W StringBuffermetodach są zsynchronizowane. Oznacza to, że jednocześnie może działać na nich tylko jeden wątek. Jeśli jest więcej niż jeden wątek, drugi wątek będzie musiał poczekać na zakończenie pierwszego, a trzeci będzie musiał poczekać na zakończenie pierwszego i drugiego itd. Powoduje to, że proces jest bardzo wolny, a tym samym wydajność w przypadkuStringBuffer jest niska.

Z drugiej strony StringBuildernie jest zsynchronizowany. Oznacza to, że wiele wątków może jednocześnie działać na tym samym StringBuilderobiekcie. To sprawia, że ​​proces jest bardzo szybki, a zatem wydajność StringBuilderjest wysoka.


3

A Stringjest niezmiennym obiektem, co oznacza, że wartość nie może być zmieniona podczas gdyStringBuffer jest zmienna.

StringBufferSą synchronizowane tym samym nić bezpieczny natomiast StringBuildernie nadaje się i jest przeznaczona do jednorazowego gwintowany przypadkach.


3
tylko dlatego, że StringBuffer ma zsynchronizowany kod, niekoniecznie oznacza, że ​​StringBuffer jest wątkowo bezpieczny. Rozważ następujący przykład: StringBuffer testingBuffer = "stackoverflow"; Teraz Thread-1 próbuje dołączyć „1” do testowania bufora, a Thread-2 próbuje dołączyć „2” do testowania bufora. Teraz, mimo że metoda append () jest zsynchronizowana, nie możesz być pewien, czy wartością testBuffer będzie „stackoverflow12” czy „stackoverflow21”. W rzeczywistości Oracle zaleca używanie programu budującego łańcuchy zamiast bufora łańcuchowego. Mam nadzieję, że to pomogło :)
Biman Tripathy

2

Główną różnicą jest StringBuffersynchronizacja, ale tak nie StringBuilderjest. Jeśli musisz użyć więcej niż jednego wątku, zalecamy StringBuffer, ale jak na szybkość wykonywania StringBuilderjest większa niż StringBuffer, ponieważ nie jest zsynchronizowana.


4
StringBuffer jest bezpieczny tylko dla wątków, jeśli wykonasz na nim tylko jedną operację. Nie polecałbym używania go w wielu wątkach, ponieważ bardzo trudno jest go naprawić.
Peter Lawrey,

@PeterLawrey co masz na myśli? :-)
Tamad Lang

1
@ b16db0 Mam na myśli, że większość zastosowań StringBuffer nie jest bezpieczna dla wątków, ponieważ wykonują wiele wywołań bez zewnętrznej synchronizacji, przez co klasa jest raczej bezcelowa.
Peter Lawrey

@PeterLawrey ah to tak, jakby StringBuffer nadal potrzebuje zsynchronizowanego środowiska.
Tamad Lang

2

Sprawdź elementy wewnętrzne zsynchronizowanej metody append StringBufferi niezsynchronizowanej metody append z StringBuilder.

StringBuffer :

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

public synchronized StringBuffer append(Object obj) {
    super.append(String.valueOf(obj));
    return this;
}

public synchronized StringBuffer append(String str) {
    super.append(str);
    return this;
}

StringBuilder :

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

public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

Ponieważ dodatek jest synchronized,StringBuffer ma narzut wydajności w porównaniu do StrinbBuilderscenariusza wielowątkowego. Tak długo, jak nie udostępniasz bufora wielu wątkom, użyj tego StringBuilder, co jest szybkie ze względu na brak synchronizedmetod dołączania.


1

Oto wynik testu wydajności dla String vs StringBuffer vs StringBuilder . Wreszcie StringBuilder wygrał test. Poniżej znajduje się kod testu i wynik.

Kod :

private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test

int loop = 100000;
long start = 0;

// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
  str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");

// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
  sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");

// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
  sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");

  }

Wykonaj mnie na ideone

Wynik :

100000 iteracji dla dodania pojedynczego tekstu

String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms

10000 iteracji dla dodania pojedynczego tekstu

String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms

1
  • StringBuffer jest bezpieczny dla wątków, ale StringBuilder nie jest bezpieczny dla wątków.
  • StringBuilder jest szybszy niż StringBuffer.
  • StringBuffer jest synchronizowany, podczas gdy StringBuilder nie jest synchronizowany.

1

StringBuffer jest zsynchronizowany i wątkowo bezpieczny, StringBuilder nie jest synchronizowany i szybszy.


Różnicę tę podano we wszystkich innych odpowiedziach na to pytanie. Czy możesz wyróżnić coś nowego?
Nico Haase,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.