Dopiero co spotkałem StringBuilder
się po raz pierwszy i byłem zaskoczony, ponieważ Java ma już bardzo potężną String
klasę, która umożliwia dołączanie.
Dlaczego druga String
klasa?
Gdzie mogę dowiedzieć się więcej StringBuilder
?
Dopiero co spotkałem StringBuilder
się po raz pierwszy i byłem zaskoczony, ponieważ Java ma już bardzo potężną String
klasę, która umożliwia dołączanie.
Dlaczego druga String
klasa?
Gdzie mogę dowiedzieć się więcej StringBuilder
?
Odpowiedzi:
String
nie pozwala na dołączanie. Każda metoda wywoływana na a String
tworzy nowy obiekt i zwraca go. Dzieje się tak, ponieważ String
jest niezmienna - nie może zmienić swojego stanu wewnętrznego.
Z drugiej strony StringBuilder
jest zmienny. Kiedy wywołujesz append(..)
, zmienia wewnętrzną tablicę znaków, zamiast tworzyć nowy obiekt ciągu.
Dlatego bardziej efektywne jest posiadanie:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i ++) {
sb.append(i);
}
zamiast str += i
, co spowodowałoby utworzenie 500 nowych obiektów łańcuchowych.
Zauważ, że w przykładzie używam pętli. Jak zauważa helios w komentarzach, kompilator automatycznie tłumaczy wyrażenia takie String d = a + b + c
jak np
String d = new StringBuilder(a).append(b).append(c).toString();
Zauważ również, że istnieje StringBuffer
dodatek do StringBuilder
. Różnica polega na tym, że ta pierwsza ma zsynchronizowane metody. Jeśli używasz go jako zmiennej lokalnej, użyj StringBuilder
. Jeśli zdarzy się, że jest możliwe, aby uzyskać do niego dostęp przez wiele wątków, użyj StringBuffer
(to rzadsze)
Oto konkretny przykład, dlaczego -
int total = 50000;
String s = "";
for (int i = 0; i < total; i++) { s += String.valueOf(i); }
// 4828ms
StringBuilder sb = new StringBuilder();
for (int i = 0; i < total; i++) { sb.append(String.valueOf(i)); }
// 4ms
Jak widać różnica w wydajności jest znacząca.
s = sb.ToString();
na koniec należy uwzględnić czas na wykonanie a, więc przynajmniej zrobiłeś to samo w obu przykładach (wynik to a string
).
Klasa String jest niezmienna, podczas gdy StringBuilder jest zmienna.
String s = "Hello";
s = s + "World";
Powyższy kod utworzy dwa obiekty, ponieważ ciąg znaków jest niezmienny
StringBuilder sb = new StringBuilder("Hello");
sb.append("World");
Powyższy kod utworzy tylko jeden obiekt, ponieważ StringBuilder nie jest niezmienny.
Lekcja: Ilekroć istnieje potrzeba wielokrotnego manipulowania / aktualizowania / dołączania String, przejdź do StringBuilder jako wydajnego w porównaniu do String.
StringBuilder służy do budowania ciągów. A konkretnie budowanie ich w bardzo wydajny sposób. Klasa String jest dobra do wielu rzeczy, ale w rzeczywistości ma naprawdę straszną wydajność podczas składania nowej struny z mniejszych części struny, ponieważ każda nowa struna jest całkowicie nową, ponownie przydzieloną struną. (Jest to niezmienne ) StringBuilder utrzymuje taką samą sekwencję w miejscu i modyfikuje go ( modyfikowalnych ).
Klasa StringBuilder jest zmienna iw przeciwieństwie do String, umożliwia modyfikowanie zawartości ciągu bez konieczności tworzenia większej liczby obiektów String, co może zwiększyć wydajność, gdy mocno modyfikujesz ciąg. Istnieje również odpowiednik dla StringBuilder o nazwie StringBuffer, który jest również zsynchronizowany, więc jest idealny dla środowisk wielowątkowych.
Największym problemem związanym z String jest to, że każda operacja, którą na nim wykonasz, zawsze zwróci nowy obiekt, na przykład:
String s1 = "something";
String s2 = "else";
String s3 = s1 + s2; // this is creating a new object.
StringBuilder jest dobry, gdy masz do czynienia z większymi ciągami. Pomaga poprawić wydajność.
Oto artykuł , który okazał się pomocny.
Szybkie wyszukiwanie w Google mogłoby Ci pomóc. Teraz zatrudniłeś 7 różnych osób, aby wyszukały za Ciebie w Google. :)
Mówiąc dokładniej, dodanie wszystkich ciągów StringBuilder to O (N), a dodanie String to O (N ^ 2). Sprawdzanie kodu źródłowego odbywa się wewnętrznie poprzez zachowanie zmiennej tablicy znaków. StringBuilder wykorzystuje technikę duplikacji długości tablicy, aby osiągnąć amortyzowaną wydajność O (N ^ 2), kosztem potencjalnego podwojenia wymaganej pamięci. Możesz wywołać trimToSize na końcu, aby rozwiązać ten problem, ale zwykle obiekty StringBuilder są używane tylko tymczasowo. Możesz dodatkowo poprawić wydajność, zapewniając dobre początkowe przypuszczenie ostatecznego rozmiaru ciągu.
Wydajność.
Za każdym razem, gdy łączysz ciągi, zostanie utworzony nowy ciąg. Na przykład:
String out = "a" + "b" + "c";
Tworzy to nowy, tymczasowy ciąg, kopiuje do niego „a” i „b”, dając w wyniku „ab”. Następnie tworzy kolejny nowy, tymczasowy ciąg, kopiuje do niego „ab” i „c”, dając w wyniku „abc”. Wynik ten jest następnie przypisywany do out
.
Rezultatem jest algorytm Schlemiela the Paintera o złożoności czasowej O (n²) (kwadratowej).
StringBuilder
z drugiej strony umożliwia dołączanie ciągów w miejscu, zmieniając rozmiar ciągu wyjściowego w razie potrzeby.
Java ma String, StringBuffer i StringBuilder:
Ciąg: jest niezmienny
StringBuffer: jego Mutable i ThreadSafe
StringBuilder: jego Mutable, ale nie ThreadSafe, wprowadzone w Javie 1.5
Ciąg np:
public class T1 {
public static void main(String[] args){
String s = "Hello";
for (int i=0;i<10;i++) {
s = s+"a";
System.out.println(s);
}
}
}
}
wyjście: zostanie utworzonych 10 różnych ciągów zamiast tylko 1 ciągu.
Helloa
Helloaa
Helloaaa
Helloaaaa
Helloaaaaa
Helloaaaaaa
Helloaaaaaaa
Helloaaaaaaaa
Helloaaaaaaaaa
Helloaaaaaaaaaa
StringBuilder np: Zostanie utworzony tylko 1 obiekt StringBuilder.
public class T1 {
public static void main(String[] args){
StringBuilder s = new StringBuilder("Hello");
for (int i=0;i<10;i++) {
s.append("a");
System.out.println(s);
}
}
}