Zakładając ciąg A i B:
a += b
a = a.concat(b)
Czy pod maską są takie same?
Oto konkat dekompilowany jako odniesienie. Chciałbym również móc dekompilować +
operatora, aby zobaczyć, co to robi.
public String concat(String s) {
int i = s.length();
if (i == 0) {
return this;
}
else {
char ac[] = new char[count + i];
getChars(0, count, ac, 0);
s.getChars(0, i, ac, count);
return new String(0, count + i, ac);
}
}
java
string
concatenation
shsteimer
źródło
źródło
+
można go zdekompilować.StringBuffer
lubStringBuilder
- (wątek jest niebezpieczny, a więc szybszy, zamiast tegoOdpowiedzi:
Nie do końca.
Po pierwsze, istnieje niewielka różnica w semantyce. Jeśli
a
taknull
, toa.concat(b)
rzuca a,NullPointerException
alea+=b
potraktuje oryginalną wartośća
tak, jakby byłanull
. Ponadtoconcat()
metoda akceptuje tylkoString
wartości, podczas gdy+
operator po cichu przekształci argument na ciąg znaków (używająctoString()
metody dla obiektów). Zatemconcat()
metoda jest bardziej rygorystyczna pod względem tego, co akceptuje.Aby zajrzeć pod maską, napisz prostą lekcję
a += b;
Teraz zdemontuj za pomocą
javap -c
(zawartego w Sun JDK). Powinieneś zobaczyć listę zawierającą:Więc
a += b
jest odpowiednikiemconcat
Metoda powinna być szybsza. Jednak przy większej liczbie ciągówStringBuilder
metoda wygrywa, przynajmniej pod względem wydajności.Kod źródłowy
String
iStringBuilder
(i jego podstawowa klasa pakietu) jest dostępny w src.zip Sun JDK. Możesz zobaczyć, że budujesz tablicę char (zmieniając rozmiar w razie potrzeby), a następnie wyrzucasz ją podczas tworzenia finałuString
. W praktyce przydzielanie pamięci jest zaskakująco szybkie.Aktualizacja: Jak zauważa Paweł Adamski, wydajność zmieniła się w najnowszym HotSpot.
javac
nadal generuje dokładnie ten sam kod, ale kompilator kompilatora bajtów oszukuje. Proste testowanie całkowicie kończy się niepowodzeniem, ponieważ cały kod jest wyrzucany. SumowanieSystem.identityHashCode
(nieString.hashCode
) pokazuje, żeStringBuffer
kod ma niewielką przewagę. Zastrzega się możliwość zmian po wydaniu kolejnej aktualizacji lub w przypadku korzystania z innej maszyny JVM. Od @lukaseder , listy intrinsics HotSpot JVM .źródło
javap -c
w skompilowanej klasie, która go używa. (Och, jak w odpowiedzi. Musisz tylko zinterpretować demontaż kodu bajtowego, co nie powinno być takie trudne.)StringBuilder
nawet podczas łączenia dwóch ciągów? JeśliString
uwzględnione zostaną statyczne metody konkatenacji do czterech łańcuchów lub wszystkich łańcuchów wString[]
, kod może dołączyć do czterech łańcuchów z dwoma przydziałami obiektów (wynikString
i jego podstawachar[]
, bez jednego nadmiarowego) oraz dowolną liczbą ciągów z trzema przydziałami (String[]
wynikString
, a podkładchar[]
, a tylko pierwsze z nich są zbędne). Jak to jest, za pomocąStringBuilder
woli w najlepszym wymagają cztery przydziały, i będzie wymagać kopiowania każdy znak dwukrotnie.Niyaz ma rację, ale warto również zauważyć, że specjalny operator + może zostać przekształcony w coś bardziej wydajnego przez kompilator Java. Java ma klasę StringBuilder, która reprezentuje nie-bezpieczny dla wątków, modyfikowalny ciąg. Podczas wykonywania szeregu konkatenacji ciągów kompilator Java konwertuje po cichu
w
co w przypadku dużych łańcuchów jest znacznie bardziej wydajne. O ile mi wiadomo, nie dzieje się tak, gdy używasz metody concat.
Jednak metoda konkat jest bardziej wydajna podczas łączenia pustego ciągu z istniejącym ciągiem. W takim przypadku JVM nie musi tworzyć nowego obiektu String i może po prostu zwrócić istniejący. Zobacz dokumentację konkat, aby to potwierdzić.
Jeśli więc bardzo martwisz się wydajnością, powinieneś użyć metody concat podczas konkatenacji możliwie pustych łańcuchów, a także użyć + w przeciwnym razie. Jednak różnica w wydajności powinna być znikoma i prawdopodobnie nie powinieneś się o to martwić.
źródło
String
- jak mówisz,concat
ma jeden wyjątek, gdy konkatujesz pustyString
.Przeprowadziłem podobny test jak @marcio, ale z następującą pętlą:
Na wszelki wypadek też wrzuciłem
StringBuilder.append()
. Każdy test był uruchamiany 10 razy, z 100 000 powtórzeń dla każdego uruchomienia. Oto wyniki:StringBuilder
wygrywa ręce w dół. Wynik czasu zegara wynosił 0 dla większości przebiegów, a najdłuższy trwał 16ms.a += b
zajmuje około 40000 ms (40 s) dla każdego uruchomienia.concat
wymaga tylko 10000ms (10s) na przebieg.Nie zdekompilowałem jeszcze klasy, aby zobaczyć elementy wewnętrzne lub uruchomić ją za pomocą profilera, ale podejrzewam, że
a += b
spędza dużo czasu na tworzeniu nowych obiektów,StringBuilder
a następnie konwertowaniu ich z powrotemString
.źródło
+
używa się dwóch ciągów, czy są jakieś przypadki, w których użycieStringBuilder
jest lepsze niż byłobyString.valueOf(s1).concat(s2)
? Masz pojęcie, dlaczego kompilatory nie wykorzystałyby tego ostatniego [lub zrezygnowałyby zvalueOf
wywołania w przypadkach, w którychs1
wiadomo, że nie ma wartości null]?Większość odpowiedzi pochodzi z 2008 roku. Wygląda na to, że z czasem wszystko się zmieniło. Moje najnowsze testy porównawcze wykonane przy użyciu JMH pokazują, że na Javie 8
+
jest około dwa razy szybsza niżconcat
.Mój punkt odniesienia:
Wyniki:
źródło
String
nigdy nie zawierała funkcji statycznej do utworzenia łańcucha przez połączenie elementówString[]
. Użycie+
do konkatenacji 8 łańcuchów przy użyciu takiej funkcji wymagałoby skonstruowania i późniejszego porzuceniaString[8]
, ale byłby to jedyny obiekt, który musiałby zostać skonstruowany porzucony, podczas gdy użycieStringBuilder
wymagałoby skonstruowania i porzuceniaStringBuilder
instancji oraz co najmniej jednegochar[]
magazynu zaplecza.String.join()
metody statyczne zostały dodane w Javie 8, jako szybkie opakowania składni w całejjava.util.StringJoiner
klasie.+
zmieniła się, aby korzystać z takich funkcji?+
aby z niej skorzystać) wymagałaby niestety tego, co deweloperzy Java są gotowi zmienić, niestety.Tom ma rację, opisując dokładnie, co robi operator +. Tworzy tymczasowe
StringBuilder
, dołącza części i kończy ztoString()
.Jednak wszystkie dotychczasowe odpowiedzi ignorują efekty optymalizacji środowiska uruchomieniowego HotSpot. W szczególności te tymczasowe operacje są rozpoznawane jako wspólny wzorzec i są zastępowane bardziej wydajnym kodem maszynowym w czasie wykonywania.
@marcio: Utworzyłeś mikro-benchmark ; w przypadku nowoczesnych maszyn JVM nie jest to prawidłowy sposób profilowania kodu.
Przyczyną optymalizacji czasu pracy jest to, że wiele z tych różnic w kodzie - nawet w zakresie tworzenia obiektów - jest zupełnie innych, gdy HotSpot się uruchomi. Jedynym sposobem, aby się upewnić, jest profilowanie kodu na miejscu .
Wreszcie wszystkie te metody są w rzeczywistości niezwykle szybkie. Może to być przypadek przedwczesnej optymalizacji. Jeśli masz kod, który często łączy łańcuchy, sposób na uzyskanie maksymalnej prędkości prawdopodobnie nie ma nic wspólnego z tym, których operatorów wybierasz, a zamiast tego używasz algorytmu!
źródło
Co powiesz na proste testy? Użyłem kodu poniżej:
"a + b"
Wersja wykonana w 2500ms .a.concat(b)
Wykonywane 1200ms .Testowane kilka razy. The
concat()
wersji zajęło średnio połowę czasu.Ten wynik mnie zaskoczył, ponieważ
concat()
metoda zawsze tworzy nowy ciąg znaków (zwraca „new String(result)
”. Dobrze wiadomo, że:Dlaczego kompilator nie był w stanie zoptymalizować tworzenia łańcucha w kodzie „a + b”, wiedząc, że zawsze zapewniał ten sam ciąg? Mogłoby to uniknąć tworzenia nowego ciągu. Jeśli nie wierzysz powyższemu stwierdzeniu, sprawdź sam.
źródło
Zasadniczo istnieją dwie ważne różnice między + a
concat
metodą.Jeśli używasz metody concat , wówczas możesz łączyć tylko łańcuchy, podczas gdy w przypadku operatora + możesz także łączyć łańcuch z dowolnym typem danych.
Na przykład:
W takim przypadku wyjście powinno wynosić 10 Cześć .
W powyższym przypadku musisz podać dwa ciągi obowiązkowe.
Druga i główna różnica między + a concat polega na tym, że:
Przypadek 1: Załóżmy, że łączę te same ciągi z operatorem konkat w ten sposób
W tym przypadku całkowita liczba obiektów utworzonych w puli wynosi 7 takich jak to:
Przypadek 2:
Teraz zamierzam skonkatować te same łańcuchy za pomocą operatora +
W powyższym przypadku całkowita liczba utworzonych obiektów to tylko 5.
W rzeczywistości, gdy łączymy łańcuchy za pomocą operatora + , wówczas utrzymuje on klasę StringBuffer, aby wykonać to samo zadanie w następujący sposób:
W ten sposób utworzy tylko pięć obiektów.
To są podstawowe różnice między + a metodą konkat . Cieszyć się :)
źródło
String s="I"+"am"+"good"+"boy"; String s2 = "go".concat("od"); System.out.println(s2 == s2.intern());
odciskitrue
, co oznacza, że"good"
nie było w puli ciągów przed wywołaniemintern()
Dla kompletności chciałem dodać, że definicja operatora „+” znajduje się w JLS SE8 15.18.1 :
O implementacji JLS mówi:
Sądząc po „kompilatorze Java, można użyć klasy StringBuffer lub podobnej techniki w celu zmniejszenia”, różne kompilatory mogą generować inny kod bajtowy.
źródło
Operatora + mogą pracować między łańcucha i łańcuch, odbarwiającego, liczb całkowitych, podwójne lub pływaka wartość typu danych. Po prostu konwertuje wartość na reprezentację ciągu przed konkatenacją.
Operatora concat może być dokonana jedynie na i ze strun. Sprawdza zgodność typu danych i zgłasza błąd, jeśli nie są one zgodne.
Poza tym podany kod działa tak samo.
źródło
Nie wydaje mi się
a.concat(b)
jest zaimplementowany w String i myślę, że implementacja niewiele się zmieniła od wczesnych maszyn Java.+
Realizacja operacji zależy od wersji Java i kompilator. Obecnie+
jest wdrażany za pomocą,StringBuffer
aby operacja była jak najszybsza. Może w przyszłości to się zmieni. We wcześniejszych wersjach java+
operacja na Strings była znacznie wolniejsza, ponieważ dawała wyniki pośrednie.Wydaje mi się, że
+=
jest implementowany za pomocą+
i podobnie zoptymalizowany.źródło
Gdy używasz +, prędkość maleje wraz ze wzrostem długości łańcucha, ale gdy używasz konkat, prędkość jest bardziej stabilna, a najlepszą opcją jest użycie klasy StringBuilder, która ma stabilną prędkość, aby to zrobić.
Chyba rozumiesz dlaczego. Ale najlepszym sposobem na tworzenie długich łańcuchów jest użycie StringBuilder () i append (), albo prędkość będzie niedopuszczalna.
źródło