Какова стоимость производительности присвоения одного строкового значения с использованием +?

StackOverflow https://stackoverflow.com/questions/601804

Вопрос

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

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 строку, затем новую, объединяющую значение, а затем еще одну, снова объединяющую значения?

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

Это было полезно?

Решение

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

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

(См. спецификацию для получения точных сведений о «требованиях, перечисленных выше» :)

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

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

Другие советы

Действительно, в 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, третье издание, (и тот же раздел, упомянутый в Ответ Джона Скита), мне не удалось найти никаких ссылок на то, должен ли компилятор объединять многострочные строки. String в единый String, поэтому такое поведение, вероятно, зависит от реализации компилятора.

Проверьте это сами.В коде 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

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

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

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

Для кода С#:

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 
}

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

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

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

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

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 и скомпилированы разными компиляторами.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top