Kolejne pytanie: dlaczego używasz SB tylko do jednej iteracji pętli? Czy jest inna wewnętrzna iteracja? SB nie jest warta, jeśli chcesz po prostu zrobić A + B + C + D (kompilator Java wewnętrznie użyje SB). Pomaga, jeśli chcesz warunkowo dodać części ciągów, ale poza tym ... po prostu użyj „+”.
helios
Odpowiedzi:
135
Jedną z opcji jest użycie metody usuwania w następujący sposób:
StringBuffer sb =newStringBuffer();for(int n =0; n <10; n++){
sb.append("a");// This will clear the buffer
sb.delete(0, sb.length());}
Inna opcja (oczyszczanie bitów) wykorzystuje setLength (int len) :
Coś mniej bzdurnego byłoby po prostu zadeklarowanie StringBuffer wewnątrz pętli.
Mark Elliot,
11
Ach, myślę, że sb.setLength (0); jest czystszy i wydajniejszy niż deklarowanie go wewnątrz pętli. Twoje rozwiązanie jest sprzeczne z korzyścią dla wydajności wynikającą z używania StringBuffer ...
Jon,
6
Myślę, że korzyść z wydajności wynika ze zmienności łańcucha, a nie z zapisania instancji. oto szybki test iteracji 1e8: pętla wewnętrzna (2,97 s): ideone.com/uyyTL14w , pętla zewnętrzna (2,87 s): ideone.com/F9lgsIxh
Mark Elliot
6
A propos wydajności: O ile kod nie jest dostępny w scenariuszu wielowątkowym, należy używać StringBuilder zamiast StringBuffer - zobacz javadoc: „Tam, gdzie jest to możliwe, zaleca się, aby ta klasa była używana zamiast StringBuffer, ponieważ będzie ona szybsza pod większość wdrożeń ”.
Rahel Lüthy
4
Jedyną zaletą tworzenia SB na zewnątrz jest brak utraty jego wewnętrznego (potencjalnie długiego) znaku []. Jeśli w pierwszym iteratorze wystarczająco urósł, druga pętla nie będzie musiała zmieniać rozmiaru znaku []. Jednak aby uzyskać przewagę, „metoda czyszczenia” będzie musiała zachować rozmiar wewnętrznej tablicy. setLength robi to, ale ustawia także \ u0000 wszystkie nieużywane znaki w SB, więc jest mniej wydajne niż po prostu tworzenie nowego SB z dobrą początkową pojemnością. Deklarowanie wewnątrz pętli jest lepsze.
helios
48
Najłatwiejszym sposobem ponownego użycia StringBufferjest użycie metodysetLength()
sb.setLength(0);// It will just discard the previous data, which will be garbage collected later.
Albo użyj:
sb.delete(0, sb.length());// A bit slower as it is used to delete sub sequence.
UWAGA
Unikaj deklarowania StringBufferlub StringBuilderobiektów w pętli, w przeciwnym razie utworzy nowe obiekty z każdą iteracją. Tworzenie obiektów wymaga zasobów systemowych, miejsca, a także czasu. Dlatego na dłuższą metę unikaj deklarowania ich w pętli, jeśli to możliwe.
Proponuję stworzyć nowy StringBuffer(lub nawet lepszy StringBuilder) dla każdej iteracji. Różnica w wydajności jest naprawdę nieistotna, ale Twój kod będzie krótszy i prostszy.
Jeśli masz jakiekolwiek dowody na taką różnicę w wydajności, udostępnij je. (Z przyjemnością zobaczę również statystyki dotyczące miejsc, w których Java jest najczęściej używana i według której definicji „głównie”.)
Eli Acherkan,
1
Powszechnie wiadomo, że alokacja (nowe słowo kluczowe w Javie) jest droższa niż zwykła zmiana niektórych pól tego samego obiektu. W przypadku „większości”, które można by zastąpić, jest ponad 1,5 miliarda urządzeń z Androidem, wszystkie wykorzystujące Javę.
Louis CAD
1
Zgadzam się, że w niektórych przypadkach czytelność kodu jest ważniejsza niż wydajność, ale w tym przypadku jest to tylko jedna linia kodu! Możesz też uruchomić test porównawczy, który udowodni, że alokacja i tworzenie obiektów oraz zbieranie śmieci są droższe niż brak robienia tego w ogóle. Ponieważ jesteśmy w pętli, jest to więcej niż istotne.
Louis CAD
1
Zgodziłem się również z poglądem Knutha, ale jego punkt widzenia nie zawsze jest prawdziwy. Dodanie tylko jednej linii w celu potencjalnego zwiększenia liczby cykli procesora i pamięci nie jest absolutnie złe. Zabierasz ten pomysł zbyt prosto. Zauważ, że pętla jest zwykle powtarzana wiele razy. Pętla może być powtarzana tysiące razy, co może pochłaniać cenne megabajty na telefonie komórkowym (a także na serwerze lub komputerze), jeśli nie zostanie odpowiednio zoptymalizowane.
Louis CAD
1
Myślę, że oboje dostatecznie jasno przedstawiliśmy nasze punkty widzenia i uważam, że dalsza dyskusja nie będzie korzystna dla tej sekcji komentarzy. Jeśli uważasz, że moja odpowiedź jest niepoprawna, wprowadzająca w błąd lub niekompletna, to ty - lub ktokolwiek - z całą pewnością możesz ją edytować i / lub przegłosować.
Już dobra odpowiedź. Po prostu dodaj wynik testu porównawczego dla różnicy wydajności StringBuffer i StringBuild, użyj nowej instancji w pętli lub użyj setLength (0) w pętli.
Podsumowanie jest następujące: w dużej pętli
StringBuilder jest znacznie szybszy niż StringBuffer
Tworzenie nowej instancji StringBuilder w pętli nie różni się od metody setLength (0). (setLength (0) ma bardzo, bardzo małą przewagę niż tworzenie nowej instancji.)
StringBuffer jest wolniejszy niż StringBuilder, tworząc nowe wystąpienie w pętli
setLength (0) StringBuffer jest znacznie wolniejsza niż tworzenie nowej instancji w pętli.
Bardzo prosty test porównawczy (po prostu ręcznie zmieniłem kod i wykonałem inny test):
publicclassStringBuilderSpeed{publicstaticfinalchar ch[]=newchar[]{'a','b','c','d','e','f','g','h','i'};publicstaticvoid main(String a[]){int loopTime =99999999;long startTime =System.currentTimeMillis();StringBuilder sb =newStringBuilder();for(int i =0; i < loopTime; i++){for(char c : ch){
sb.append(c);}
sb.setLength(0);}long endTime =System.currentTimeMillis();System.out.println("Time cost: "+(endTime - startTime));}
}
Nowe wystąpienie StringBuilder w pętli: Koszt czasu: 3693, 3862, 3624, 3742
StringBuilder setLength: Time cost: 3465, 3421, 3557, 3408
Nowa instancja StringBuffer w pętli: Koszt czasu: 8327, 8324, 8284
Ponownie StringBuilder setLength, aby upewnić się, że mój labtop nie ma problemu z używaniem tak długiego zestawu StringBuffer setLength :-) Koszt czasu: 3448
Odpowiedzi:
Jedną z opcji jest użycie metody usuwania w następujący sposób:
Inna opcja (oczyszczanie bitów) wykorzystuje setLength (int len) :
Zobacz Javadoc, aby uzyskać więcej informacji:
źródło
Najłatwiejszym sposobem ponownego użycia
StringBuffer
jest użycie metodysetLength()
public void setLength(int newLength)
Możesz mieć taki przypadek
źródło
setLength
zamiastsetlength
.Masz dwie możliwości:
Albo użyj:
Albo użyj:
UWAGA
Unikaj deklarowania
StringBuffer
lubStringBuilder
obiektów w pętli, w przeciwnym razie utworzy nowe obiekty z każdą iteracją. Tworzenie obiektów wymaga zasobów systemowych, miejsca, a także czasu. Dlatego na dłuższą metę unikaj deklarowania ich w pętli, jeśli to możliwe.źródło
źródło
Proponuję stworzyć nowy
StringBuffer
(lub nawet lepszyStringBuilder
) dla każdej iteracji. Różnica w wydajności jest naprawdę nieistotna, ale Twój kod będzie krótszy i prostszy.źródło
Stosowanie:
ze względu na czytelność uważam, że to najlepsze rozwiązanie.
źródło
Już dobra odpowiedź. Po prostu dodaj wynik testu porównawczego dla różnicy wydajności StringBuffer i StringBuild, użyj nowej instancji w pętli lub użyj setLength (0) w pętli.
Podsumowanie jest następujące: w dużej pętli
Bardzo prosty test porównawczy (po prostu ręcznie zmieniłem kod i wykonałem inny test):
}
Nowe wystąpienie StringBuilder w pętli: Koszt czasu: 3693, 3862, 3624, 3742
StringBuilder setLength: Time cost: 3465, 3421, 3557, 3408
Nowa instancja StringBuffer w pętli: Koszt czasu: 8327, 8324, 8284
StringBuffer setLength Koszt czasu: 22878, 23017, 22894
Ponownie StringBuilder setLength, aby upewnić się, że mój labtop nie ma problemu z używaniem tak długiego zestawu StringBuffer setLength :-) Koszt czasu: 3448
źródło
Myślę, że ten kod jest szybszy.
źródło