путаница: строка неизменна, поэтому не используйте для объединения

1

JAVA: Я хочу, чтобы очистить, используя String, как это

String str = " SELECT "
           + "field1, "
           + "field2, "
           + "field3  "
           + " FROM table1; ";

в порядке или не использовать этот способ.

спрашивая, основываясь на передовой практике, касающейся String, чтобы не использовать для конкатенации.

ЭТО ОЧЕНЬ КРАТКИЙ ВОПРОС, НО ВЕСЬ МЫ ИМЕЕМ ОЧЕНЬ ОЧЕНЬ БОЛЬШОЙ ЗАПРОС. Это просто пример. ТАК ТОЛЬКО ХОТИТЕ ПОДТВЕРДИТЬ, ЧТО НЕ ЛЮБОЙ НЕПРАВИЛЬНО.

  • 2
    Что именно вас беспокоит? Это не выглядит очень читаемым для меня, но это время компиляции постоянной, так конкатенация не будет происходить во время выполнения ... используя StringBuilder сделает работу этого хуже, если что - нибудь. Даже если объединение было выполнено во время выполнения, очень маловероятно, что объединение нескольких таких строк будет значительным по сравнению с выполнением SQL-запроса (который предположительно является контекстом). Конкатенация в цикле обычно плохая идея, улучшенная с помощью StringBuilder - но это другой вопрос.
  • 0
    @JonSkeet, если вопрос касается заранее определенной конкатенации данных, то вы правы
Показать ещё 1 комментарий
Теги:
string
concatenation

6 ответов

2
Лучший ответ

Это нормально и точно так же, как написать его как одну строку:

String str = " SELECT field1, field2, field3   FROM table1; ";

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

  • 0
    но другие говорят, что он создает объект StringBuilder для каждой конкатенации.
  • 0
    @ murtaza.webdev Ну, остальные не правы ... если вам нужны доказательства, скомпилируйте ваш код, а затем декомпилируйте его с javap инструмента javap , включенного в JDK. Примечание: я специально говорю о конкатенации строковых литералов . Конечно, если вы на самом деле не объединяете литералы, тогда ответ будет другим. (Обратите внимание, что ни один из других ответов не согласен с тем, что я сказал - прочитайте их внимательно ...).
3

String конкатенация с + оператором может рассматриваться как плохая практика, в определенных контекстах, то есть, если он не может быть автоматически заменен StringBuilder вызовов во время компиляции.

В общем случае, если ваше поле является константой или инициализировано только один раз, то конкатенация String с + отлично.

Однако, если вы динамически строит String и перекручивание/рекурсии, вы лучше с StringBuilder (или StringBuffer для поточно-сцеплений).

  • 0
    что ты скажешь об ответе @jesper
  • 2
    @ murtaza.webdev Я думаю, что ответ Джеспера только частично правильный. Если ваше поле является константой или инициализировано только один раз, следовательно, в результате получается String которая объединяется с + только один раз с литералами или константами, компилятор заменит его своим сцепленным значением. Однако нет, если часть вашей конкатенации является переменной. В этом случае компилятор может использовать вместо него StringBuilder или оставить конкатенацию как есть, в зависимости от сложности.
1

То, что вы здесь делаете, на самом деле не так. Это неудобно, хотя по этим причинам:

  • Недопустимость: все операторы и котировки делают это раздражающим читать

  • Ошибка: она слишком проста при изменении этого значения, чтобы опустить пробел из подстроки и сломать запрос

  • Неудобно: вы не можете копировать запрос в инструмент SQL без необходимости останавливать и удалять все операторы и кавычки.

Вы могли бы извлечь такой SQL файл в файл конфигурации, либо файл свойств, либо XML (с использованием CDATA) могли бы работать. Вы можете увидеть примеры в Spring Integration - внешние запросы JDBC

1

+ считается неудачным, когда вы соединяете строки в цикле. Допустим, у вас есть

String s = "f";
for (int i=0; i<100; i++){
    s = s + "o";
}

В этом случае

s = s + "o";

будут скомпилированы как

s = new StringBuilder(f).append("o").toString();

поэтому на каждой итерации вы создаете новый StringBuilder, вы копируете текущий контент s в него, затем добавляете o и воссоздаете новый экземпляр String, вызывая toString который вы храните в ссылке s. Как вы видите, это много всего, что нужно сделать, особенно для копирования и создания нового экземпляра String, время выполнения которого зависит от длины строки.

Предпочтительный способ сделать это - создать собственный StringBuilder, добавить то, что вы хотите в цикле, и после завершения цикла создать новый объект String из содержимого StringBuilder. Что-то вроде

StringBuilder sb = new StringBuilder("f");
for (int i=0; i<100; i++){
    sb.append("o");
}
String s = sb.toString();

Но в вашем случае, поскольку вы работаете с константой компиляции, которая не может быть изменена, поэтому компилятор может выяснить, что

String str = " SELECT "
           + "field1, "
           + "field2, "
           + "field3  "
           + " FROM table1; ";

может быть не чем иным, как " SELECT field1, field2, field3 FROM table1; " поэтому он будет сцеплен во время компиляции, поэтому ваша str будет скомпилирована как

String str = " SELECT field1, field2, field3   FROM table1; ";
  • 0
    что ты скажешь об ответе @jesper
  • 1
    @ murtaza.webdev Это правильно. Конкатенация констант времени компиляции может быть выполнена во время компиляции, например, String result = "foo"+"bar" , приведет к тому же байт-коду, что и String result = "foobar" , но она не будет работать так же для String s1 = "foo"; String s2 = "bar"; String result = s1 + s2; ни String result = "foo"+s2; (поскольку s1 и s2 здесь не являются постоянными времени компиляции), в этом случае результат должен быть сгенерирован во время выполнения, и компилятор изменит ваш код для использования StringBuilder .
1

Ваш пример хорош, потому что он включает только литералы, а компилятор будет выполнять конкатенацию во время компиляции.


Но если бы у вас было:

String str = " SELECT "
           + "field1, "
           + someVariable
           + "field3  "
           + " FROM table1; ";

... тогда компилятор мог бы только обрабатывать часть этого для вас, приводя к этому во время выполнения:

String str = " SELECT field1, "
           + someVariable
           + "field3   FROM table1; ";

То, как это происходит во время выполнения, - это StringBuilder, который звучит великолепно, но, к сожалению, делается довольно неэффективно, фактически это:

StringBuilder sb1 = new StringBuilder();
sb1.append(" SELECT field1, ");
sb1.append(someVariable);
String temp = sb1.toString();
StringBuilder sb2 = new StringBuilder();
sb2.append(temp);
sb2.append("field3   FROM table1; ");
String str = sb2.toString();

Мало того, он создает несколько StringBuilder экземпляров и делать ненужные звонки в toString, но он использует конструктор по умолчанию, который только выделяет достаточно места для строки в 16 символов в его массиве ( в прошлом я проверил). Поэтому StringBuilder, вероятно, придется перераспределять свой внутренний массив хотя бы один раз. Блех, да? (Ждать его...)

Сравните с тем, что вы могли бы сделать сами:

String str = (new StringBuilder(200))
                .append(" SELECT " +
                        "field1, ")
                .append(someVariable)
                .append("field3  " +
                        " FROM table1; ")
                .toString();

Это намного эффективнее.

Но лучше? Это ужасно смотреть и ужасно поддерживать. Вы должны были бы делать это в трудной петле, чтобы это имело значение с точки зрения производительности.

Так что это "лучше", если у вас есть проблема с производительностью, которая помогает решить эту проблему.

Это не "лучше", если вы этого не сделаете, так как код намного менее ясен.

Ничто из этого не имеет значения, если вы имеете дело только с литералами.

  • 0
    что ты скажешь об ответе @jesper
  • 0
    @ murtaza.webdev: Я думаю, что это неполно. Вся вторая часть моего ответа выше есть причина. Я предполагаю, что вы не просто используете строковые литералы, а если нет, то об этом вторая часть моего ответа.
1

Я очень сомневаюсь, что field1 и field2 и table1 известны заранее, я предполагаю, что они являются параметрами для некоторой функции.

В этом случае вместо этого вы должны использовать StringBuilder. Даже если вы согласитесь со знаком "плюс", вы все равно (почти всегда) получите StringBuilder, просто посмотрите на байт-код. Вот ссылка:

"Реализация может решить выполнить преобразование и конкатенацию за один шаг, чтобы избежать создания и затем отбрасывания промежуточного объекта String. Чтобы увеличить производительность повторной конкатенации строк, компилятор Java может использовать класс StringBuffer или аналогичный метод для уменьшения числа промежуточные объекты String, созданные путем оценки выражения. " , 15.18.1

Просто помните, что будет штраф за выполнение, если вы будете петлять.

  • 0
    что ты скажешь об ответе @jesper
  • 0
    @ murtaza.webdev Джеспер прав. Проблема здесь в следующем: знаете ли вы field1, filed2 и т. Д. Заранее? Или вы принимаете их как параметры метода?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню