Prefacio
Entre los desarrolladores de Java, la alta ocupación de recursos de las cuerdas es a menudo un tema candente.
Discutamos en profundidad por qué ocupa altos recursos.
En Java, un objeto de cadena es inmutable, lo que significa que una vez que se crea, ya no puede cambiarlo. Entonces, cuando empalmamos cadenas, creamos una nueva cadena, y la vieja está marcada por el recolector de basura.
Si procesamos millones de cuerdas, generamos millones de cuerdas adicionales para ser procesadas por el recolector de basura.
En la mayoría de los tutoriales, puede ver que usar + signos a cadenas de empalme generará múltiples cadenas, lo que dará como resultado un bajo rendimiento. Se recomienda usar StringBuffer/StringBuilder para empalmarse.
¿Pero este es realmente el caso?
Este artículo ha realizado el siguiente experimento en JDK8:
public static void main (string [] args) {string dult = ""; resultado += "Algunos datos más"; System.out.println (resultado); }Descompilar a través de Javap -C para obtener:
Código: 0: ALOAD_0 // Presione 'esto' en la pila 1: Invokespecial #1 // Invoke Object Class Constructor // Pop 'this' Ref de la pila 4: return // Regreso del constructor público estatic void main (java.lang.string []); Código: 0: LDC #2 // Cargue constante #2 en la pila 2: store_1 // Crear var local VAR a partir de la pila (Pop #2) 3: Nuevo #3 // Presione la nueva referencia de StringBuilder en la pila 6: dup // valor duplicado en la parte superior de la pila 7: Invokespecial #4 // Invoca el constructor de stringBuilder // Objeto Pop Variable 10: ALOAD_1 /////1 Presion InvokeVirtual #5 // Invoke Method StringBuilder.append () // Pop Obj Reference + Parameter // Push Result (StringBuilder Ref) 14: LDC #6 // Presione "algunos datos más" en el stack 16: InvokeVirtual #5 // Invoke StringBuilder.append // Pop Twice, Push Result 19: Invokevirtual #7 // Invoke StringBuilder. 22: store_1 // Crear var local a partir de la pila (pop #6) 23: getstatic #8 // system de valores push.
Puede ver que el compilador Java optimiza el bytecode generado, crea automáticamente un StringBuilder y realiza operaciones de apertura.
Dado que las subcadenas de la cadena final ya se conocen en el momento de la compilación, el compilador Java realizará la optimización anterior en este caso. Esta optimización se llama optimización de concatenación de cadena estática y se ha habilitado desde JDK5.
¿Eso significa que después de JDK5, ya no necesitamos generar manualmente StringBuilder, y podemos lograr el mismo rendimiento a través del signo +?
Probemos las cadenas de empalme dinámicamente:
Las cadenas de empalme dinámicas se refieren a sustras que solo se conocen en tiempo de ejecución. Por ejemplo, agregar una cadena a un bucle:
public static void main (string [] args) {string dult = ""; para (int i = 0; i <10; i ++) {resultado+= "algunos datos más"; } System.out.println (resultado); }También descompilado:
Código: 0: ALOAD_0 // Presione 'esto' en la pila 1: Invokespecial #1 // Invoke Object Class Constructor // Pop 'this' Ref de la pila 4: return // Regreso del constructor público estatic void main (java.lang.string []); Código: 0: LDC #2 // Cargue constante #2 en la pila 2: store_1 // Crear var local Var desde la pila, Pop #2 3: iconst_0 // Valor 0 en la pila 4: istore_2 // Valor pop y almacenarlo en Var Local Var 5: ILOAD_2 // PUSH VAR LOCAL EN LA PISTA 6: I2D // CONVERTO INTO A DOBLE ON // TOP de Top Of STACK (PUSH (PUSH PUSH PUSPLACIÓN (PUSH PUSH SUSPURSE (PUSH SUSPURSE) ldc2_w #3 // presione constante 10e6 en la pila 10: dcmpg // compare dos dobles en la parte superior de la pila // pop dos veces, presione el resultado: -1, 0 o 1 11: ifge 40 // si el valor en la parte superior de la pila es mayor // o igual a 0 (pop una vez) // rama a la instrucción en el código 40 14: nuevo #5 // Push Newbuilder Ref. arriba de la pila 18: Invokespecial #6 // Invoke StringBuilder Constructor // Referencia de objeto Pop 21: Aload_1 // Push Local Var 1 (String vacía) // En la pila 22: InvokeVirtual #7 // Invoke StringBuilder.append // Pop Obj Ref + Param, Push Result 25: LDC #8 // PUSH "ALGUNOS datos" En el stack 27: STACK #7 /7 /7 /7. StringBuilder.append // Pop obj ref + param, Push Result 30: InvokeVirtual #9 // Invoke StringBuilder.ToString // Referencia de objeto Pop 33: store_1 // Crear var local var desde pila (pop) 34: iinc 2, 1 // Incrementa Variable local 2 por 1 37: GoTo 5 // Move a instrucción en el código 5: Getstatic #10 // Push Value System.out. Aload_1 // presione la var 1 local (cadena de resultados) 44: InvokeVirtual #11 // Invoke Method printStream.println () // Pop Twice (Object Ref + Parameter) 47: return // return void desde el método
Puede ver que el StringBuilder era nuevo a los 14 años, pero a los 37 años, Goto 5. Durante el bucle, la optimización no se logró y se generaban constantemente nuevos StringBuilders.
Entonces el código anterior es similar:
String result = ""; for (int i = 0; i <10; i ++) {StringBuilder tmp = new StringBuilder (); tmp.append (resultado); tmp.append ("algunos datos más"); resultado = tmp.ToString ();} System.out.println (resultado);Puede ver que los nuevos StringBuilders se generan constantemente, y a través de la tostración, el StringBuilder original ya no se hace referencia, como basura, y también aumenta el costo de GC.
Por lo tanto, en uso real, cuando no puede distinguir si una cadena es estática o dinámica, use StringBuilder.
Referencia:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.