четверг, 25 мая 2017 г.

Избегайте конкатенации строк

«конкатенация строк», и это плохая практика:
// bad practice, don't reuse!
String text = "Hello, " + name + "!";
Некоторые могут сказать, что это медленный процесс, главным образом потому, что части результирующей строки копируются несколько раз. Действительно, для каждого оператора + класс String выделяет в памяти новый блок и копирует все, что в нем есть; Плюс присоединяемый суффикс. Это верно, но здесь дело не в этом.

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

Некоторые говорят, что конкатенированные строки не являются локализуемыми, потому что в разных языках текстовые блоки во фразе могут располагаться в другом порядке. Пример выше не может быть переведен на, скажем, русский язык, где мы хотели бы поставить имя перед «привет». Нам нужно будет локализовать весь блок кода, а не просто переводить фразу.

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

Давайте посмотрим на эти альтернативные методы. Я бы порекомендовал три из них (в порядке предпочтения): String.format (), Apache StringUtils и Guava Joiner.

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

String.Format ()

String.format () - мой любимый вариант. Он облегчает понимание и изменение текстовых фраз. Это метод статической утилиты, который отображает sprintf () из C. Это позволяет вам построить строку, используя шаблон и заместители:

String text = String.format ("Здравствуйте,% s!", Имя);

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

String msg = "Dear " + customer.name()
  + ", your order #" + order.number()
  + " has been shipped at " + shipment.date()
  + "!";


Этот выглядит гораздо красивее, не так ли:

String msg = String.format(
  "Dear %1$s, your order #%2$d has been shipped at %3$tR!",
  customer.name(), order.number(), shipment.date()
);


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

% 1 $ s, στις% 3 $ tR στείλαμε την παραγγλλα σου με αριθμό #% 2 $ d!

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

Apache StringUtils.join ()

Когда текст довольно длинный (длиннее ширины экрана), я бы рекомендовал вам использовать класс утилиты StringUtils от Apache commons-lang3:

import org.apache.commons.lang3.StringUtils;
String xml = StringUtils.join(
  "<?xml version='1.0'?>",
  "<html><body>",
  "<p>This is a test XHTML document,",
  " which would look ugly,",
  " if we would use a single line,"
  " or string concatenation or String format().</p>"
  "</body></html>"
);

Необходимость включения дополнительной зависимости JAR к вашему пути к классам может рассматриваться как недостаток этого метода (получение его последних версий в Maven Central):

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
</dependency>

Столяр Гуавы


Подобную функциональность предоставляет Joiner из Гуавы Google:

import com.google.common.base.Joiner;
String text = Joiner.on('').join(
  "WE HAVE BUNNY.\n",
  "GATHER ONE MILLION DOLLARS IN UNMARKED ",
  "NON-CONSECUTIVE TWENTIES.\n",
  "AWAIT INSTRUCTIONS.\n",
  "NO FUNNY STUFF"
);
Это немного менее удобно, чем StringUtils, так как вы всегда должны предоставлять столяр (символ или строку, помещенную между текстовыми блоками).

Опять же, в этом случае требуется зависимость:

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
</dependency>

Да, в большинстве случаев все эти методы работают медленнее, чем простая простая конкатенация. Тем не менее, я твердо верю, что компьютеры дешевле людей. Я имею в виду, что время, потраченное программистами на понимание и модификацию уродливого кода, намного дороже, чем стоимость дополнительного сервера, который сделает красиво написанный код более быстрым.

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

Комментариев нет:

Отправить комментарий