Pregunta

Muchas veces me he preguntado esto, ¿hay un costo de rendimiento al dividir una cadena en varias líneas para aumentar la legibilidad cuando inicialmente se asigna un valor a una cadena? Sé que las cadenas son inmutables y, por lo tanto, siempre se debe crear una nueva cadena. Además, el costo de rendimiento es realmente irrelevante gracias al hardware realmente rápido de hoy (a menos que esté en algún bucle diabólico). Entonces, por ejemplo:

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.";

¿Cómo maneja esto el compilador de JVM o .Net y otras optimizaciones? ¿Creará una sola cadena? ¿O creará 1 cadena, luego una nueva concatenación del valor y luego otra concatenación de los valores nuevamente?

Esto es para mi propia curiosidad.

¿Fue útil?

Solución

Esto está garantizado por la especificación de C # para que sea idéntico a la creación de la cadena en un solo literal, porque es una constante de tiempo de compilación. De la sección 7.18 de la especificación C # 3:

  

Cada vez que una expresión cumple el   requisitos enumerados anteriormente, el   la expresión se evalúa en   tiempo de compilación. Esto es cierto incluso si el   expresión es una subexpresión de un   expresión más grande que contiene   construcciones no constantes.

(Consulte la especificación para conocer los detalles exactos de " los requisitos enumerados arriba " :)

La especificación del lenguaje Java lo especifica cerca de la parte inferior de sección 3.10.5 :

  

Cadenas calculadas por constante   las expresiones (& # 167; 15.28) se calculan en   tiempo de compilación y luego tratado como si   eran literales.

Otros consejos

De hecho, en Java, el compilador convertirá la String en una 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();
    }
}

Se compila en:

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 se puede ver, se carga una sola línea en la línea 4, en lugar de cargar varias instancias de String .

Editar: El archivo fuente se compiló con javac versión 1.6.0_06. Mirando La especificación del lenguaje Java, tercera edición , (y la misma sección mencionada en Respuesta de Jon Skeet ), no pude encontrar ninguna referencia sobre si un compilador debería concatenar una String de varias líneas en una sola String , por lo que este comportamiento probablemente sea específico de la implementación del compilador.

Prueba esto por ti mismo. En código C # (Java equivalente también funcionaría):

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

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

Verá que el resultado es verdadero .

Como comentario aparte, verá que la cadena también está internada en el conjunto de cadenas del tiempo de ejecución:

bool interned = object.ReferenceEquals(x, string.Intern(x)); // true

Sin compensación de rendimiento. La optimización del compilador combinará eso en una sola cadena (al menos en Java).

Hasta donde puedo recordar, esto no creará múltiples cadenas, solo la única.

El .NET IL equivalente para complementar respuesta de coobird :

Para el 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);

Una compilación de depuración produce:

.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 
}

Entonces, como puede ver, es una cadena.

Mientras todas las cadenas sean constantes (como en su ejemplo), en Java (e imagino C #) el compilador convierte esto en una sola cadena.

Solo tiene problemas de rendimiento con + si concatena muchas cadenas dinámicas, como en un bucle. En este caso, use un StringBuilder o StringBuffer.

Descargo de responsabilidad: esto es cierto para Java. Supongo que es cierto para c #

Javac no solo creará una sola cadena, sino que la JVM usará una cadena para todas las demás cadenas que contengan el mismo 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: serán el mismo objeto String en tiempo de ejecución, incluso si están en diferentes clases en diferentes JARS, compilados por diferentes compiladores.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top