Правильный способ использования StringBuilder в SQL

Я только что нашел в моем проекте сборку sql, подобную этой:

return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString(); 

Достигает ли этот StringBuilder свою цель, то есть уменьшает использование памяти?

Я сомневаюсь, что, поскольку в конструкторе используется «+» (оператор String concat). Будет ли такой объем памяти использоваться с использованием String, как в коде ниже? я понял, он отличается при использовании StringBuilder.append() .

 return "select id1, " + " id2 " + " from " + " table"; 

Оба оператора равны в использовании памяти или нет? Просьба уточнить.

Заранее спасибо!

Редактировать:

Кстати, это не мой код . Нашел его в старом проекте. Кроме того, запрос не так мал, как в моем примере. 🙂

objective использования StringBuilder – сокращение памяти. Достигнуто ли это?

Нет, совсем нет. Этот код не использует StringBuilder правильно. (Я думаю, что вы неверно процитировали его, но, конечно же, нет котировок вокруг id2 и table ?)

Обратите внимание, что целью (как правило) является сокращение памяти, а не общая память, чтобы сделать жизнь немного проще в сборщике мусора.

Будет ли это память равной использованию String, как показано ниже?

Нет, это приведет к большему сбою памяти, чем просто прямое цитирование, которое вы цитировали. (До тех пор, пока оптимизатор JVM не увидит, что явный StringBuilder в коде не нужен и оптимизирует его, если это возможно.)

Если автор этого кода хочет использовать StringBuilder (есть аргументы, но и против, см. Примечание в конце этого ответа), лучше сделать это правильно (здесь я предполагаю, что на самом деле нет котировок вокруг id2 и table ):

 StringBuilder sb = new StringBuilder(some_appropriate_size); sb.append("select id1, "); sb.append(id2); sb.append(" from "); sb.append(table); return sb.toString(); 

Обратите внимание, что я перечислил some_appropriate_size в конструкторе some_appropriate_size , так что он начинается с достаточной емкости для полного содержимого, которое мы собираемся добавить. Размер по умолчанию, используемый, если вы не указываете один из них, составляет 16 символов , что обычно слишком мало и приводит к тому, что StringBuilder должен выполнять перераспределение, чтобы сделать себя больше (IIRC, в Sun / Oracle JDK, он удваивает себя [или больше, если он знает, что ему нужно больше, чтобы удовлетворить конкретное приложение] каждый раз, когда он заканчивается из комнаты).

Возможно, вы слышали, что конкатенация строк будет использовать StringBuilder под обложками, если скомпилирована с компилятором Sun / Oracle. Это верно, он будет использовать один StringBuilder для общего выражения. Но он будет использовать конструктор по умолчанию, а это означает, что в большинстве случаев ему придется перераспределять ресурсы. Это легче читать. Обратите внимание, что это не относится к серии конкатенаций. Так, например, это использует один StringBuilder :

 return "prefix " + variable1 + " middle " + variable2 + " end"; 

Это примерно соответствует:

 StringBuilder tmp = new StringBuilder(); // Using default 16 character size tmp.append("prefix "); tmp.append(variable1); tmp.append(" middle "); tmp.append(variable2); tmp.append(" end"); return tmp.toString(); 

Так что все в порядке, хотя конструктор по умолчанию и последующее перераспределение (ы) не являются идеальными, вероятность того, что он достаточно хорош, и конкатенация намного читаема.

Но это только для одного выражения. Для этого используются несколько StringBuilder :

 String s; s = "prefix "; s += variable1; s += " middle "; s += variable2; s += " end"; return s; 

Это становится чем-то вроде этого:

 String s; StringBuilder tmp; s = "prefix "; tmp = new StringBuilder(); tmp.append(s); tmp.append(variable1); s = tmp.toString(); tmp = new StringBuilder(); tmp.append(s); tmp.append(" middle "); s = tmp.toString(); tmp = new StringBuilder(); tmp.append(s); tmp.append(variable2); s = tmp.toString(); tmp = new StringBuilder(); tmp.append(s); tmp.append(" end"); s = tmp.toString(); return s; 

… это довольно уродливо.

Однако важно помнить, что во всех случаях, кроме очень немногих случаев, это не имеет значения и требует читаемости (что улучшает ремонтопригодность) является предпочтительным, если не учитывать особую проблему производительности.

Когда у вас уже есть все «штуки», которые вы хотите добавить, нет смысла использовать StringBuilder . Использование StringBuilder и конкатенация строк в том же вызове, что и в вашем примере кода, еще хуже.

Это было бы лучше:

 return "select id1, " + " id2 " + " from " + " table"; 

В этом случае конкатенация строк на самом деле происходит во время компиляции , поэтому она эквивалентна четному упрощению:

 return "select id1, id2 from table"; 

Использование new StringBuilder().append("select id1, ").append(" id2 ")....toString() фактически будет препятствовать производительности в этом случае, поскольку он заставляет конкатенацию выполняться во время выполнения , а не во время компиляции . К сожалению.

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

У меня есть статья о String / StringBuffer которую я написал некоторое время назад – до StringBuilder . Тем не менее, принципы применимы и к StringBuilder .

[[Здесь есть несколько хороших ответов, но я обнаружил, что им все еще не хватает информации. ]]

 return (new StringBuilder("select id1, " + " id2 " + " from " + " table")) .toString(); 

Итак, как вы указываете, пример, который вы даете, является упрощенным, но давайте проанализируем его в любом случае. Что здесь происходит, так это то, что компилятор действительно работает здесь, потому что "select id1, " + " id2 " + " from " + " table" – это все константы. Таким образом, это превращается в:

 return new StringBuilder("select id1, id2 from table").toString(); 

В этом случае, очевидно, нет смысла использовать StringBuilder . Вы также можете:

 // the compiler combines these constant strings return "select id1, " + " id2 " + " from " + " table"; 

Однако, даже если вы добавляли какие-либо поля или другие не константы, тогда компилятор использовал бы внутренний StringBuilder – вам не нужно определять его:

 // an internal StringBuilder is used here return "select id1, " + fieldName + " from " + tableName; 

Под обложками это превращается в код, который приблизительно эквивалентен:

 StringBuilder sb = new StringBuilder("select id1, "); sb.append(fieldName).append(" from ").append(tableName); return sb.toString(); 

Действительно, единственный раз, когда вам нужно напрямую использовать StringBuilder вы имеете условный код. Например, код, который выглядит следующим образом, отчаялся для StringBuilder :

 // 1 StringBuilder used in this line String query = "select id1, " + fieldName + " from " + tableName; if (where != null) { // another StringBuilder used here query += ' ' + where; } 

В первой строке + используется один экземпляр StringBuilder . Затем += использует другой экземпляр StringBuilder . Это более эффективно:

 // choose a good starting size to lower chances of reallocation StringBuilder sb = new StringBuilder(64); sb.append("select id1, ").append(fieldName).append(" from ").append(tableName); // conditional code if (where != null) { sb.append(' ').append(where); } return sb.toString(); 

В другой раз, когда я использую StringBuilder я создаю строку из нескольких вызовов методов. Затем я могу создать методы, которые принимают аргумент StringBuilder :

 private void addWhere(StringBuilder sb) { if (where != null) { sb.append(' ').append(where); } } 

Когда вы используете StringBuilder , вы должны следить за любым использованием + в то же время:

 sb.append("select " + fieldName); 

Это + приведет к StringBuilder другого внутреннего StringBuilder . Это, конечно же, должно быть:

 sb.append("select ").append(fieldName); 

Наконец, как указывает @TJrowder, вы всегда должны угадывать размер StringBuilder . Это позволит сэкономить на количестве объектов char[] созданных при увеличении размера внутреннего буфера.

Вы правы в предположении, что цель использования построителя строк не достигается, по крайней мере, не в полной мере.

Однако, когда компилятор видит выражение "select id1, " + " id2 " + " from " + " table" он испускает код, который фактически создает StringBuilder за кулисами и добавляет к нему, поэтому конечный результат не так уж плох после завершения ,

Но, конечно, любой, кто смотрит на этот код, должен думать, что он немного отсталый.

В коде, который вы опубликовали, не будет никаких преимуществ, поскольку вы злоупотребляете StringBuilder. В обоих случаях вы создаете ту же строку. Используя StringBuilder, вы можете избежать операции + в Strings с помощью метода append . Вы должны использовать его так:

 return new StringBuilder("select id1, ").append(" id2 ").append(" from ").append(" table").toString(); 

В Java тип String является неотъемлемой последовательностью символов, поэтому, когда вы добавляете две строки, VM создает новое значение String с объединенными операндами.

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

Это дает некоторые полезные функции, так как изменение содержимого последовательности символов, передаваемых как параметр внутри другого метода, что вы не можете сделать со строками.

 private void addWhereClause(StringBuilder sql, String column, String value) { //WARNING: only as an example, never append directly a value to a SQL String, or you'll be exposed to SQL Injection sql.append(" where ").append(column).append(" = ").append(value); } 

Дополнительная информация на http://docs.oracle.com/javase/tutorial/java/data/buffers.html

Вы также можете использовать MessageFormat

  • StringBuilder vs Конкатенация строк в toString () в Java
  • Interesting Posts

    Как сериализовать / десериализовать словаря `из пользовательского XML, не использующего XElement?

    Как я могу получить доступ к разделам EXT3 в Windows 7?

    как использовать getListView () в действии?

    Почему логические 4 байта в .NET?

    Как я могу создать Quick Style Set, который я создал?

    Список всех активных сеансов ASP.NET

    Как я могу сгладить PDF-форму XFA с помощью iTextSharp?

    Как изменить экран по умолчанию, когда у меня есть двойной экран в Windows 7?

    Закрыть jQuery UI Dialog из Iframe

    Как обнаружить кнопку отправки нажатой в нескольких сценариях кнопок отправки в одном classе Action?

    Группировать путем подсчета в Java 8 stream API

    Почему sed требует 3 обратных косых черт для регулярной обратной косой черты?

    Regex соответствует многострочному комментарию в стиле C

    Создание оглавления в файле PDF отсканированной книги

    Превосходный андроид cordova работает отлично. Но Android 4.1.2 не запускает приложение

    Давайте будем гением компьютера.