2010-10-01 12 views
13

mam kod w następujący sposób:Czy to zawsze zły pomysł, aby użyć + do łączenia ciągów

String s = ""; 
for (My my : myList) { 
    s += my.getX(); 
} 

Findbugs zawsze zgłasza błąd, kiedy to zrobić.

+1

to getX(); zwrócenie ciągu? –

+0

Nie sądzę, że to "zawsze" złe. Ale częściej nie ma alternatyw, które są lepiej dostosowane. – decompiled

+6

Zdecydowanie nie jest tak źle używać konkatenacji z +. Jest jednak źle, gdy robisz taką pętlę. – ColinD

Odpowiedz

21

użyłbym + jeśli ręcznie złączenie,

String word = "Hello"; 
word += " World!"; 

Jednak jeśli iteracji i złączenie Proponuję StringBuilder,

StringBuilder sb = new StringBuilder(); 
for (My my : myList) { 
    sb.append(my.getX()); 
} 
+7

+1 - jest to konkatenacja * w pętli *, której powinieneś unikać. –

+0

Inna kwestia: w niektórych przypadkach może być _better_ używać + w przypadku, gdy istnieją ciągi literałów łańcuchowych, ponieważ szereg połączonych literałów zostanie skompilowany jako jeden ciąg znaków. Nie jestem pozytywny, biorąc pod uwagę sposób, w jaki jest podzielony na wiele linii, ale myślę, że kompilator zoptymalizuje to do 'String word =" Hello World! ". – ColinD

+0

Stosowanie takiej konkatenacji jest w porządku, jeśli masz pewność, że nigdy, nigdy, twoja aplikacja nie zostanie zlokalizowana. Jeśli planujesz przetłumaczyć je na język obcy, skończy się to wadą lokalizacyjną. –

8

Obiekt String jest niezmienny w Javie. Każde + oznacza inny obiekt. Możesz użyć StringBuffer, aby zminimalizować ilość tworzonych obiektów.

+7

Java tłumaczy konkatenację za pomocą +, aby użyć 'StringBuilder'. Musisz tylko użyć 'StringBuilder', jeśli używasz pętli lub budujesz łańcuch za pomocą serii wywołań metod lub innych. Ponadto 'StringBuffer' ma narzut bezpieczeństwa, którego zwykle nie potrzebujesz, więc' StringBuilder' jest ogólnie lepszym wyborem. – ColinD

+5

_Tony odchodzi, aby przeczytać o StringBuilder_ –

3

Kompilator może zoptymalizować niektóre rzeczy takie jak

"foo" + "bar"

To

StringBuilder s1 = new StringBuilder(); s1.append ("foo") .endend ("bar");

Jednak jest to nadal nieoptymalne, ponieważ zaczyna się od domyślnego rozmiaru 16. Jak w przypadku wielu rzeczy, powinieneś znaleźć swoje największe wąskie gardła i przejść do następnej listy. To nie boli być w zwyczaju używania wzorca SB od samego początku, szczególnie jeśli jesteś w stanie obliczyć optymalny rozmiar inicjalizacji.

+0

właściwie * kompilator * może zoptymalizować to do "foobar" "... +1 dla znalezienia wąskiego gardła –

3

Optymalizacja przedwczesna może być zła, ponieważ często zmniejsza czytelność i jest zwykle całkowicie niepotrzebna. Użyj wartości +, jeśli jest bardziej czytelna, chyba że masz nadrzędny problem.

3

Nie jest "zawsze źle" używać "+". Korzystanie z StringBuffer wszędzie może sprawić, że kod będzie naprawdę nieporęczny.

Gdyby ktoś włożył dużo "+" w trakcie intensywnej, krytycznej czasowo pętli, byłbym zirytowany. Jeśli ktoś włożył dużo "+" w rzadko używany fragment kodu, nie obchodzi mnie to.

1

powiedziałbym zastosowanie także w następujących przypadkach:

String c = "a" + "b"

I użyć klasy StringBuilder wszędzie indziej. Jak już wspomniano w pierwszym przypadku, zostanie zoptymalizowany przez kompilator i będzie bardziej czytelny.

4

każdym razem robisz string+=string, wywołuje metodę tak:

private String(String s1, String s2) { 
    if (s1 == null) { 
     s1 = "null"; 
    } 
    if (s2 == null) { 
     s2 = "null"; 
    } 
    count = s1.count + s2.count; 
    value = new char[count]; 
    offset = 0; 
    System.arraycopy(s1.value, s1.offset, value, 0, s1.count); 
    System.arraycopy(s2.value, s2.offset, value, s1.count, s2.count); 
} 

W przypadku StringBuilder, chodzi o:

final void append0(String string) { 
    if (string == null) { 
     appendNull(); 
     return; 
    } 
    int adding = string.length(); 
    int newSize = count + adding; 
    if (newSize > value.length) { 
     enlargeBuffer(newSize); 
    } 
    string.getChars(0, adding, value, count); 
    count = newSize; 
} 

Jak można jasno stwierdzić, string + string stwarza wiele napowietrznych i moim zdaniem należy go unikać, jeśli to możliwe.Jeśli uważasz, że przy użyciu StringBuilder jest nieporęczny lub długo można po prostu zrobić metodę i używać go w sposób pośredni, jak:

public static String scat(String... vargs) { 
    StringBuilder sb = new StringBuilder(); 

    for (String str : vargs) 
     sb.append(str); 

    return sb.toString(); 
} 

i używać go lubię:

String abcd = scat("a","b","c","d"); 

W języku C# jak mi powiedziano jej o tak samo jak string.Concat();. W twoim przypadku to byłoby mądre, aby napisać przeciążenie dla scat, jak:

public static String scat(Collection<?> vargs) { 
    StringBuilder sb = new StringBuilder(); 

    for (Object str : vargs) 
     sb.append(str); 

    return sb.toString(); 
} 

Następnie można wywołać go z:

result = scat(myList) 
1

Jednym z powodów, dlaczego FindBugs powinien spierać o użyciu operatora konkatenacji (być "+" lub "+ =") to lokalizacja. Na przykład dałeś to nie jest tak oczywiste, ale w przypadku poniższego kodu jest:

String result = "Scanning found " + Integer.toString(numberOfViruses) + " viruses"; 

Jeśli ta wygląda nieco znajomo, musisz zmienić swój styl kodowania. Problem w tym, że zabrzmi świetnie po angielsku, ale może być koszmarem dla tłumaczy. Dzieje się tak dlatego, że nie można zagwarantować, że kolejność zdań będzie nadal taka sama po tłumaczeniu - niektóre języki będą tłumaczone na "1 blah blah", inne na "blah blah 3". W takich przypadkach zawsze powinieneś używać MessageFormat.format() do budowania złożonych zdań, a użycie operatora konkatenacji to oczywiście błąd internacjonalizacji.

BTW. Stawiam tutaj kolejną wadę i18n, czy mógłbyś to zauważyć?

0

Czas działania łączenia dwóch ciągów jest proporcjonalny do długości łańcuchów. Jeśli jest używany w pętli, czas działania zawsze wzrasta. Jeśli więc potrzeba połączenia w pętli, lepiej użyć StringBuilder, tak jak sugerował Anthony.

Powiązane problemy