Qual é o custo de atribuir um valor único string usando + 's desempenho
-
03-07-2019 - |
Pergunta
Muitas vezes me perguntei isso, há um custo de desempenho de dividir uma string em várias linhas para aumentar a legibilidade quando inicialmente atribuir um valor a uma string. Eu sei que strings são imutáveis ??e, portanto, uma nova string precisa ser criado de cada vez. Além disso, o custo de desempenho é realmente irrelevantes graças ao hardware muito rápido de hoje (a menos que você está em algum laço diabólico). Assim, por exemplo:
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.";
Como é que o compilador JVM ou .Net da e outras otimizações lidar com isso. Será que vai criar uma única corda? Ou ele irá criar uma corda, em seguida, um concatenando o novo valor e, em seguida, um outro concatenando os valores novamente?
Isto é para minha própria curiosidade.
Solução
Este é garantida pela C # especificação para ser idêntico ao criar a string em um único literal, porque é uma constante de tempo de compilação. De seção 7,18 do C # 3 spec:
Sempre que uma expressão cumpre a requisitos listados acima, o expressão é avaliada na em tempo de compilação. Isto é verdadeiro mesmo se o expressão é uma sub-expressão de um expressão maior que contenha construções não-constantes.
(Veja as especificações para os detalhes exatos de "os requisitos listados acima":)
O Java Specification Language especifica-lo perto da parte inferior seção 3.10.5 :
Cordas calculado pela constante expressões (§15.28) são calculados em o tempo de compilação e depois tratou-se como se eles eram literais.
Outras dicas
De fato, em Java, o compilador irá transformar o String
em uma constante.
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();
}
}
é compilado em:
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
}
Como pode ser visto, uma única linha é carregado no em linha 4, em vez de múltiplas instâncias String
a ser carregado no.
Editar: O arquivo de origem foi compilado usando javac
versão 1.6.0_06. Olhando para The Java Language Specification, terceira edição , (e a mesma secção mencionado em resposta de Jon Skeet), eu não era capaz de encontrar qualquer referência para saber se um compilador deve concatenar uma String
multi-linha em um único String
, de modo que este comportamento é específico de implementação, provavelmente compilador.
Test isso por si mesmo. No código C # (equivalente Java iria trabalhar muito):
string x = "A" + "B" + "C";
string y = "ABC";
bool same = object.ReferenceEquals(x, y); // true
Você vai ver que o resultado é true
.
Como um aparte, você vai ver que a cadeia também está internado em conjunto de cadeia do tempo de execução:
bool interned = object.ReferenceEquals(x, string.Intern(x)); // true
No desempenho troca. otimização do compilador irá mesclar isso com uma única corda (pelo menos em Java).
Tanto quanto me lembro, isso não vai criar várias cordas, apenas uma.
O equivalente .NET IL para complementar o coobird resposta :
Para código 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);
Uma compilação de depuração produz:
.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
}
Então, como você pode ver, é uma string.
Enquanto todas as cordas são constantes (como eles estão no seu exemplo), em Java (e imagino C #) os convertidos compilador isto a uma única cadeia.
Você só tem problemas de desempenho com + se você concatenar um monte de cordas dinâmicas, como em um loop. Neste caso, use um StringBuilder ou StringBuffer.
Disclaimer: Isto é verdade para Java. Gostaria de assumir o seu verdadeiro para c #
Não só javac criar uma única corda, mas a JVM vai usar uma corda para todas as outras cordas que contêm o mesmo texto.
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.
Nota:. Eles vão ser o mesmo objeto String em tempo de execução, mesmo se eles estão em diferentes classes em diferentes JARS, compilados por diferentes compiladores