Czy jest zauważalna różnica między używaniem String.format
a łączeniem ciągów w Javie?
Zwykle używam, String.format
ale czasami poślizgnę się i użyję konkatenacji. Zastanawiałem się, czy jedno jest lepsze od drugiego.
Sposób, w jaki go widzę, String.format
daje więcej mocy w „formatowaniu” łańcucha; a konkatenacja oznacza, że nie musisz się martwić o przypadkowe dodanie dodatkowych% s lub pominięcie jednego.
String.format
jest również krótszy.
Który z nich jest bardziej czytelny, zależy od tego, jak działa Twoja głowa.
java
string
concatenation
string.format
Omar Kooheji
źródło
źródło
Odpowiedzi:
Sugerowałbym, że jest to lepsza praktyka w użyciu
String.format()
. Głównym powodem jest to, żeString.format()
można go łatwiej zlokalizować dzięki tekstowi ładowanemu z plików zasobów, podczas gdy konkatenacji nie można zlokalizować bez wytworzenia nowego pliku wykonywalnego z innym kodem dla każdego języka.Jeśli planujesz lokalizację swojej aplikacji, powinieneś również przyzwyczaić się do określania pozycji argumentów dla swoich tokenów formatu:
Można to następnie zlokalizować i zamienić tokeny nazwy i czasu bez konieczności ponownej kompilacji pliku wykonywalnego w celu uwzględnienia różnych kolejności. Dzięki pozycjom argumentów możesz również ponownie użyć tego samego argumentu, nie przekazując go dwukrotnie do funkcji:
źródło
O wydajności:
Wyniki pomiaru czasu są następujące:
Dlatego konkatenacja jest znacznie szybsza niż String.format.
źródło
javap -c StringTest.class
, zobaczysz, że kompilator konwertuje „+” na StringBuilder automatycznie tylko wtedy, gdy nie jesteś w pętli. Jeśli łączenie odbywa się w jednym wierszu, jest to to samo, co użycie „+”, ale jeśli używaszmyString += "morechars";
lubmyString += anotherString;
w wielu wierszach, zauważysz, że można utworzyć więcej niż jeden StringBuilder, więc użycie „+” nie zawsze jest tak wydajne jako StringBuilder.+
nie są konwertowane na,StringBuilder.append()
ale zamiast tegonew StringBuilder()
dzieje się przy każdej iteracji.Ponieważ jest dyskusja na temat wydajności, pomyślałem, że dodam do porównania, które obejmowało StringBuilder. Jest to w rzeczywistości szybsze niż concat i oczywiście opcja String.format.
Aby uczynić to swego rodzaju porównanie jabłek z jabłkami, tworzę instancję nowego StringBuilder w pętli, a nie na zewnątrz (jest to w rzeczywistości szybsze niż wykonanie tylko jednej instancji, najprawdopodobniej z powodu narzutu związanego z ponownym przydzielaniem miejsca dla pętli dołączanej na końcu jeden konstruktor).
źródło
String
. Test StringBuilder, aby być uczciwym, wymaga ostatniego kroku, który zamienia zawartość StringBuilder w String. Robisz to dzwoniącbldString.toString()
. Mam nadzieję, że to wyjaśnia?String s = bldString.toString();
Te czasy były z konkatenacji i StringBuilder prawie na równi ze sobą:Format = 1520 millisecond
,Concatenation = 167 millisecond
,String Builder = 173 millisecond
wpadłem je w pętli i uśredniane każdy obecnie, aby uzyskać dobrą Czeska: (pre-JVM optymalizacji, postara się 10000+ pętlę kiedy mam czas)Jednym z problemów
.format
jest to, że tracisz bezpieczeństwo typu statycznego. Możesz mieć za mało argumentów dla swojego formatu i możesz mieć niewłaściwe typy dla specyfikatorów formatu - oba prowadzą do działaniaIllegalFormatException
w czasie wykonywania , więc możesz skończyć z kodem rejestrującym, który przerywa produkcję.Natomiast argumenty do
+
przetestowania przez kompilator.Historia zabezpieczeń zprintf(na którym
format
modelowana jest funkcja) jest długi i przerażający.źródło
Masz swoją odpowiedź właśnie tam.
To kwestia osobistego gustu.
Łączenie łańcuchów jest, jak sądzę, nieznacznie szybsze, ale powinno to być nieistotne.
źródło
Oto test z wieloma wielkościami próbek w milisekundach.
}
źródło
Oto taki sam test jak powyżej z modyfikacją wywołania metody toString () na StringBuilder . Poniższe wyniki pokazują, że podejście StringBuilder jest nieco wolniejsze niż łączenie String za pomocą operatora + .
plik: StringTest.java
Polecenia powłoki: (skompiluj i uruchom StringTest 5 razy)
Wyniki:
źródło
String.format()
to coś więcej niż tylko łączenie łańcuchów. Na przykład możesz wyświetlać liczby w określonych ustawieniach narodowych za pomocąString.format()
.Jeśli jednak nie zależy Ci na lokalizacji, nie ma żadnej różnicy funkcjonalnej. Być może jedno jest szybsze od drugiego, ale w większości przypadków będzie nieistotne.
źródło
Ogólnie rzecz biorąc, należy preferować łączenie łańcuchów
String.format
. Ta ostatnia ma dwie główne wady:Przez punkt 1 rozumiem, że nie jest możliwe zrozumienie, co
String.format()
robi połączenie w pojedynczym przebiegu sekwencyjnym. Zmusza się do przechodzenia między ciągiem formatu a argumentami, licząc jednocześnie pozycję argumentów. W przypadku krótkich konkatenacji nie stanowi to większego problemu. Jednak w tych przypadkach łączenie łańcuchów jest mniej szczegółowe.Przez punkt 2 rozumiem, że ważna część procesu budowania jest zakodowana w ciągu formatu (przy użyciu DSL). Używanie ciągów do reprezentowania kodu ma wiele wad. Nie jest z natury bezpieczny dla typu i komplikuje podświetlanie składni, analizę kodu, optymalizację itp.
Oczywiście przy użyciu narzędzi lub struktur zewnętrznych w stosunku do języka Java mogą się pojawić nowe czynniki.
źródło
Nie przeprowadziłem żadnych konkretnych testów porównawczych, ale sądzę, że konkatenacja może być szybsza. String.format () tworzy nowy moduł formatujący, który z kolei tworzy nowy StringBuilder (o rozmiarze tylko 16 znaków). To spora kwota narzutu, szczególnie jeśli formatujesz dłuższy ciąg, a StringBuilder wciąż musi zmieniać rozmiar.
Jednak łączenie jest mniej przydatne i trudniejsze do odczytania. Jak zawsze warto zrobić test porównawczy w kodzie, aby zobaczyć, co jest lepsze. Różnice mogą być nieistotne w aplikacji serwerowej po załadowaniu pakietów zasobów, ustawień regionalnych itp. Do pamięci i kodowaniu JIT.
Być może najlepszym rozwiązaniem byłoby utworzenie własnego narzędzia do formatowania z odpowiednio dobranym StringBuilder (Appendable) i ustawieniami regionalnymi i użycie tego, jeśli masz dużo formatowania.
źródło
Może być zauważalna różnica.
String.format
jest dość złożony i używa wyrażenia regularnego pod spodem, więc nie rób z niego nawyku, aby używać go wszędzie, ale tylko tam, gdzie jest to potrzebne.StringBuilder
byłoby o rząd wielkości szybsze (jak ktoś tutaj już zauważył).źródło
Myślę, że możemy iść z tym,
MessageFormat.format
ponieważ powinna być dobra zarówno pod względem czytelności, jak i aspektów wydajnościowych.Użyłem tego samego programu, którego użył Icaro w swojej powyższej odpowiedzi, i wzbogaciłem go o dołączony kod służący
MessageFormat
do wyjaśnienia liczb wykonania.AKTUALIZACJE:
Zgodnie z raportem SonarLint ciągi formatu formatu Printf powinny być używane poprawnie (squid: S3457)
Ponieważ
printf-style
ciągi formatu są interpretowane w czasie wykonywania, a nie sprawdzane przez kompilator, mogą zawierać błędy, które powodują tworzenie niewłaściwych ciągów. Zasada ta sprawdza się statycznie korelacjiprintf-style
ciągi formatu na ich argumentów podczas wywoływania formatu (...) metodjava.util.Formatter
,java.lang.String
,java.io.PrintStream
,MessageFormat
, ijava.io.PrintWriter
Klasy iprintf(...)
metodyjava.io.PrintStream
lubjava.io.PrintWriter
klasy.Zamieniam styl printf na nawiasy klamrowe i uzyskałem coś interesującego, jak poniżej.
Mój wniosek:
Jak podkreśliłem powyżej, użycie String.format z nawiasami klamrowymi powinno być dobrym wyborem, aby uzyskać korzyści z dobrej czytelności, a także wydajności.
źródło
Nie można porównać String Concatenation i String.Format przez powyższy program.
Możesz spróbować zmienić to również przy użyciu swojego String.Format i Concatenation w swoim bloku kodu, jak poniżej
Będziesz zaskoczony, widząc, że Format działa tutaj szybciej. Jest tak, ponieważ utworzone obiekty początkowe mogą nie zostać zwolnione i może wystąpić problem z alokacją pamięci, a tym samym wydajnością.
źródło
Przyzwyczajenie się do String.Format zajmuje trochę czasu, ale w większości przypadków jest tego warte. W świecie NRA (nigdy niczego nie powtarzaj) niezwykle przydatne jest przechowywanie tokenizowanych wiadomości (rejestrowania lub użytkownika) w bibliotece Constant (wolę, co stanowi klasę statyczną) i wywoływanie ich w razie potrzeby za pomocą String.Format bez względu na to, czy lokalizują czy nie. Próba użycia takiej biblioteki z metodą konkatenacji jest trudniejsza do odczytania, rozwiązywania problemów, korekty i zarządzania przy użyciu dowolnego podejścia wymagającego konkatenacji. Zastąpienie jest opcją, ale wątpię, czy jest wydajne. Po latach użytkowania moim największym problemem z String.Format jest to, że długość połączenia jest niewygodnie długa, gdy przekazuję go do innej funkcji (np. Msg), ale łatwo jest obejść tę funkcję za pomocą aliasu .
źródło