Всегда ли плохая идея использовать + для конкатенации строк

У меня есть код следующим образом:

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

Findbugs всегда сообщает об ошибке, когда я это делаю.

Ответы

Ответ 1

Я бы использовал +, если вы вручную конкатенируете,

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

Однако, если вы выполняете итерацию и конкатенирование, я предлагаю StringBuilder,

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

Ответ 2

Объект String неизменен в Java. Каждый + означает другой объект. Вы можете использовать StringBuffer для минимизации количества созданных объектов.

Ответ 3

Каждый раз, когда вы выполняете string+=string, он вызывает метод следующим образом:

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);
}

В случае StringBuilder он приходит к:

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;
}

Как вы можете заключить, string + string создает много накладных расходов, и, на мой взгляд, следует избегать, если это возможно. Если вы думаете, что использование StringBuilder громоздко или долго, вы можете просто сделать метод и использовать его косвенно, например:

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

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

    return sb.toString();
}

И используйте его как:

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

В С# мне говорят примерно так же, как string.Concat();. В вашем случае было бы разумно написать перегрузку для scat, например:

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

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

    return sb.toString();
}

Затем вы можете вызвать его с помощью:

result = scat(myList)

Ответ 4

Компилятор может оптимизировать некоторые вещи, такие как

"Foo" + "бар"

Для

StringBuilder s1 = new StringBuilder(); . S1.append( "Foo" ) добавить ( "штрих" );

Однако это все еще субоптимально, так как он начинается с размера по умолчанию 16. Как и во многих вещах, хотя вы должны найти свои самые большие шеи бутылки и поработать над списком. Не вредно быть в привычном использовании SB-шаблона, хотя, особенно если вы можете рассчитать оптимальный размер инициализации.

Ответ 5

Преждевременная оптимизация может быть плохой, а также часто снижает читаемость и, как правило, совершенно не нужна. Используйте +, если это более читаемо, если у вас нет основной проблемы.

Ответ 6

Не всегда "плохо" использовать "+" . Использование StringBuffer везде может сделать код действительно громоздким.

Если кто-то положил много "+" в середине интенсивного критического цикла, я был бы раздражен. Если кто-то поставил много "+" в редко используемом фрагменте кода, мне было бы все равно.

Ответ 7

Я бы сказал использовать плюс в следующем:

String c = "a" + "b"

И используйте класс StringBuilder везде. Как уже упоминалось в первом случае, он будет оптимизирован компилятором и более читабельным.

Ответ 8

Одна из причин, почему FindBugs должен спорить об использовании оператора конкатенации (будь то "+" или "+ =" ), является локализуемостью. В примере, который вы дали, это не так очевидно, но в случае следующего кода это:

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

Если это выглядит несколько знакомым, вам нужно изменить стиль кодирования. Проблема в том, что это будет отлично звучать на английском языке, но это может быть кошмаром для переводчиков. Это просто потому, что вы не можете гарантировать, что приговор будет оставаться неизменным после перевода - некоторые языки будут переведены на "1 бла-бла", а некоторые - на "бла-бла-3". В таких случаях вы всегда должны использовать MessageFormat.format() для построения сложных предложений, и использование оператора конкатенации явно является ошибкой интернационализации.

BTW. Я поставил здесь еще один дефект i18n, не могли бы вы его заметить?