Какова стоимость производительности при назначении одного строкового значения с помощью + - PullRequest
11 голосов
/ 02 марта 2009

Я часто задавался этим вопросом: есть ли затраты на производительность, если разбить строку на несколько строк, чтобы повысить удобочитаемость при первоначальном присвоении значения строке. Я знаю, что строки неизменны, и поэтому каждый раз нужно создавать новую строку. Кроме того, стоимость производительности на самом деле не имеет значения благодаря сегодняшнему действительно быстрому оборудованию (если вы не находитесь в каком-то дьявольском цикле). Так, например:

String newString = "This is a really long long long long long" +
    " long long long long long long long long long long long long " +
    " long long long long long long long long long string for example.";

Как компилятор JVM или .Net и другие оптимизации справляются с этим. Будет ли это создать одну строку? Или он создаст 1 строку, затем новое объединение значений и затем еще одно объединение значений снова?

Это для моего собственного любопытства.

Ответы [ 8 ]

28 голосов
/ 02 марта 2009

Это гарантируется тем, что спецификация C # идентична созданию строки в одном литерале, потому что это константа времени компиляции. Из раздела 7.18 спецификации C # 3:

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

(точную информацию о "перечисленных выше требованиях" см. В спецификации):

Спецификация языка Java указывает его в нижней части раздела 3.10.5 :

Строки, вычисленные по константе выражения (§15.28) вычисляются в время компиляции, а затем рассматривается как они были буквальными буквами.

14 голосов
/ 02 марта 2009

Действительно, в Java компилятор превратит String в константу.

class LongLongString
{
    public LongLongString()
    {
        String newString = "This is a really long long long long long" +
            " long long long long long long long long long long long long " +
            " long long long long long long long long long string for example.";
    }

    public static void main(String[] args)
    {
        new LongLongString();
    }
}

Составлено в:

Compiled from "LongLongString.java"
class LongLongString extends java.lang.Object{
public LongLongString();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   ldc #2; //String This is a really long long long long long long long long long long long long long long long long long  long long long long long long long long long string for example.
   6:   astore_1
   7:   return

public static void main(java.lang.String[]);
  Code:
   0:   new #3; //class LongLongString
   3:   dup
   4:   invokespecial   #4; //Method "<init>":()V
   7:   pop
   8:   return

}

Как видно, в строке 4 загружается одна строка, а не несколько String загружаемых экземпляров.

Редактировать: Исходный файл был скомпилирован с использованием javac версия 1.6.0_06. Глядя на Спецификацию языка Java, третье издание (и тот же раздел, упомянутый в ответ Джона Скита ), я не смог найти никаких ссылок на то, должен ли компилятор объединять мульти -line String в один String, так что это поведение, вероятно, зависит от реализации компилятора.

6 голосов
/ 02 марта 2009

Проверьте это сами. В коде C # (эквивалентный Java тоже будет работать):

string x = "A" + "B" + "C";
string y = "ABC";

bool same = object.ReferenceEquals(x, y); // true

Вы увидите, что результат true.

Кроме того, вы увидите, что строка также интернирована в пуле строк среды выполнения:

bool interned = object.ReferenceEquals(x, string.Intern(x)); // true
5 голосов
/ 02 марта 2009

Нет компромисса производительности. Оптимизация компилятора объединит это в одну строку (по крайней мере, в Java).

3 голосов
/ 02 марта 2009

Эквивалент .NET IL для дополнения ответ Coobird :

Для кода C #:

string s = "This is a really long long long long long" +
    " long long long long long long long long long long long long " +
    " long long long long long long long long long string for example.";
Console.WriteLine(s);

Отладочная компиляция выдает:

.method public hidebysig static void Main(string[] args) cil managed
{
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
  .maxstack 1
  .locals init (
      [0] string str)
  L_0000: ldstr "This is a really long long long long long long long long long long long long long long long long long  long long long long long long long long long string for example."
  L_0005: stloc.0 
  L_0006: ldloc.0 
  L_0007: call void [mscorlib]System.Console::WriteLine(string)
  L_000c: ret 
}

Итак, как вы видите, это одна строка.

3 голосов
/ 02 марта 2009

Насколько я помню, это не создаст несколько строк, только одну.

2 голосов
/ 02 марта 2009

Пока все строки постоянны (как в вашем примере), в Java (и я представляю C #) компилятор преобразует это в одну строку.

Проблемы с производительностью возникают только при +, если вы объединяете много динамических строк, например, в цикле. В этом случае используйте StringBuilder или StringBuffer.

0 голосов
/ 03 марта 2009

Отказ от ответственности: это верно для Java. Я бы предположил, что это правда для c #

Мало того, что javac создаст одну строку, но JVM будет использовать одну строку для всех других строк, содержащих тот же текст.

String a = "He" + "llo th"+ "ere";
String b = "Hell" + "o the"+ "re";
String c = "Hello" +" "+"there";
assert a == b; // these are the same String object.
assert a == c; // these are the same String object.

Примечание: они будут тем же объектом String во время выполнения, даже если они находятся в разных классах в разных JARS, скомпилированных разными компиляторами.

...