Préface
Parmi les développeurs de Java, l'occupation élevée des ressources des chaînes est souvent un sujet brûlant.
Discutons en profondeur pourquoi il occupe des ressources élevées.
Dans Java, un objet String est immuable, ce qui signifie qu'une fois qu'il est créé, vous ne pouvez plus le changer. Ainsi, lorsque nous épissons les cordes, nous créons une nouvelle chaîne et l'ancienne est marquée par le collecteur des ordures.
Si nous traitons des millions de chaînes, nous générons des millions de chaînes supplémentaires à traiter par le collecteur des ordures.
Dans la plupart des tutoriels, vous pouvez voir que l'utilisation de signes + pour épisser les chaînes générera plusieurs chaînes, ce qui entraînera de mauvaises performances. Il est recommandé d'utiliser StringBuffer / StringBuilder pour épisser.
Mais est-ce vraiment le cas?
Cet article a fait l'expérience suivante dans JDK8:
public static void main (string [] args) {string result = ""; Résultat + = "quelques données supplémentaires"; System.out.println (résultat); }Décomposant à travers Javap -C pour obtenir:
Code: 0: ALOAD_0 // Push 'This' On to the Stack 1: InvokeSpecial # 1 // Invoque Constructeur de classe d'objets // pop 'this' ref From the Stack 4: return // return du constructeur public static void main (java.lang.string []); Code: 0: LDC # 2 // Chargez la constante # 2 sur la pile 2: Store_1 // Créer un var local à partir de la pile (Pop # 2) 3: Nouveau # 3 // Push New StringBuilder Ref on Stack 6: DUP // DUPLICAL Valeur en haut de l'empilement 7: invoquer # # 4 // Push Local Variable Confortor // Pop Objet Reference 10: ALOAD_1 // PUST LOCAL VARIAY CONTRAINT // Invoque la méthode stringbuilder.append () // Référence POP OBJ + paramètre // push result (StringBuilder Ref) 14: LDC # 6 // push "quelques autres données" sur la pile 16: invokevirtual # 5 // invoquer StringBuilder.APPEND // POP TWICE, PUSH Result 19: invokeVirtual # 7 // invoke StringBuilder.Tostring: inhud.; 22: Store_1 // Créer un var local à partir de la pile (pop # 6) 23: GetStatic # 8 // PUSH VALING System.out: printStream 26: Aload_1 // Push Local Variable contenant # 6 27: InvokeVirtual # 9 // Invoke Method PrintStream.println () // Pop Twice (Object Ref + Paramètre) 30: Retour // Return Void à partir de la méthode
Vous pouvez voir que le compilateur Java optimise le bytecode généré, crée automatiquement un stringbuilder et effectue des opérations d'ajout.
Étant donné que les sous-chaînes de la chaîne finale sont déjà connues au moment de la compilation, le compilateur Java effectuera l'optimisation ci-dessus dans ce cas. Cette optimisation est appelée optimisation de concaténation statique statique et a été activée depuis JDK5.
Cela signifie-t-il qu'après JDK5, nous n'avons plus besoin de générer manuellement StringBuilder, et nous pouvons atteindre les mêmes performances via le signe +?
Essayons d'épisser dynamiquement les chaînes:
Les chaînes d'épissage dynamiques se réfèrent aux sous-chaînes qui ne sont connues qu'au moment de l'exécution. Par exemple, l'ajout d'une chaîne à une boucle:
public static void main (string [] args) {string result = ""; for (int i = 0; i <10; i ++) {result + = "quelques données plus"; } System.out.println (résultat); }Également décompilé:
Code: 0: ALOAD_0 // Push 'This' On to the Stack 1: InvokeSpecial # 1 // Invoque Constructeur de classe d'objets // pop 'this' ref From the Stack 4: return // return du constructeur public static void main (java.lang.string []); Code: 0: LDC # 2 // Chargez la constante # 2 sur la pile 2: Store_1 // Créer un var local à partir de la pile, pop # 2 3: iconst_0 // Push Valeur 0 sur la pile 4: istore_2 // Valeur pop et la stocker dans Var 5: Iload_2 // push local var 2 sur la pile 6: i2d // convertir INT à double sur // Top of Stack (Pop + push) 7: ldc2_ // pousse constante 10e6 sur la pile 10: dcmpg // comparer deux doubles en haut de la pile // pop deux fois, push Résultat: -1, 0 ou 1 11: ifge 40 // si la valeur en haut de la pile est plus grande // que ou égale à 0 (pop une fois) // branche à l'instruction au code 40 14: Nouveau # 5 // Push Stringbuilder Ref on Stack 17: dup // // Invoque StringBuilder Constructeur // Référence de l'objet POP 21: Aload_1 // push local var 1 (String vide) // à la pile 22: invokevirtual # 7 // invoquer StringBuilder.APPEND // POP OBJ REF + PARAM, PUSH Result 25: LDC # 8 // PUSH "SUPTO Param, Push Résultat 30: InvokeVirtual # 9 // Invoquez StringBuilder.ToString // Référence d'objet POP 33: Store_1 // Créer un var local à partir de Stack (POP) 34: IINC 2, 1 // Incrément Variable locale 2 par 1 37: GOTO 5 // Déplacer à l'instruction à Code 5 40: GetStatic # 10 // Push Valed System. 44: Invokevirtual # 11 // Invoke Method PrintStream.println () // Pop Twice (Object Ref + Paramètre) 47: Retour // retour void de la méthode
Vous pouvez voir que le StringBuilder était nouveau à 14 ans, mais à 37, Goto 5. Pendant la boucle, l'optimisation n'a pas été réalisée et de nouveaux constructeurs de cordes étaient constamment générés.
Le code ci-dessus est donc similaire:
String result = ""; for (int i = 0; i <10; i ++) {StringBuilder tmp = new StringBuilder (); tmp.append (résultat); tmp.append ("quelques données supplémentaires"); result = tmp.toString ();} System.out.println (résultat);Vous pouvez voir que de nouveaux Builders String sont constamment générés, et grâce à ToString, le STRACKBUILDER original ne sera plus référencé, en tant que déchets, et augmente également le coût GC.
Par conséquent, dans une utilisation réelle, lorsque vous ne pouvez pas distinguer si une chaîne est statique ou dynamique, utilisez StringBuilder.
Référence:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.