Je viens de trouver une construction de requête SQL comme celle-ci dans mon projet:
return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();
Cela StringBuilder
atteint-il son objectif, à savoir réduire l'utilisation de la mémoire?
J'en doute, car dans le constructeur, le «+» (opérateur de concat) est utilisé. Cela prendra-t-il la même quantité de mémoire que l'utilisation de String comme le code ci-dessous? s J'ai compris, cela diffère lors de l'utilisation StringBuilder.append()
.
return "select id1, " + " id2 " + " from " + " table";
Les deux instructions sont-elles égales dans l'utilisation de la mémoire ou non? Précisez s'il vous plaît.
Merci d'avance!
Éditer:
BTW, ce n'est pas mon code . Je l'ai trouvé dans un ancien projet. De plus, la requête n'est pas aussi petite que celle de mon exemple. :)
java
string
stringbuilder
Vaandu
la source
la source
PreparedStatement
ou quelque chose de similaire: docs.oracle.com/javase/tutorial/jdbc/basics/prepared.htmlRéponses:
Non pas du tout. Ce code n'utilise pas
StringBuilder
correctement. (Je pense que vous l'avez mal cité, cependant; il n'y a sûrement pas de citations autourid2
ettable
?)Notez que le but (généralement) est de réduire le taux de désabonnement de la mémoire plutôt que la mémoire totale utilisée, afin de faciliter un peu la vie du ramasse-miettes.
Non, cela causera plus de désabonnement de mémoire que le simple concat que vous avez cité. (Jusqu'à / à moins que l'optimiseur JVM ne voit que l'explicite
StringBuilder
dans le code n'est pas nécessaire et l'optimise, s'il le peut.)Si l'auteur de ce code veut utiliser
StringBuilder
(il y a des arguments pour, mais aussi contre; voir la note à la fin de cette réponse), mieux vaut le faire correctement (ici je suppose qu'il n'y a pas réellement de guillemets autourid2
ettable
):Notez que j'ai répertorié
some_appropriate_size
dans leStringBuilder
constructeur, de sorte qu'il commence avec une capacité suffisante pour le contenu complet que nous allons ajouter. La taille par défaut utilisée si vous n'en spécifiez pas un est de 16 caractères , ce qui est généralement trop petit etStringBuilder
oblige à effectuer des réallocations pour devenir plus grand (IIRC, dans le JDK Sun / Oracle, il se double [ou plus, si il sait qu'il a besoin de plus pour satisfaire un particulierappend
] chaque fois qu'il manque de place).Vous avez peut - être entendu dire que la concaténation de chaîne va utiliser un
StringBuilder
sous les couvertures si compilé avec le compilateur Sun / Oracle. C'est vrai, il en utilisera unStringBuilder
pour l'expression globale. Mais il utilisera le constructeur par défaut, ce qui signifie que dans la majorité des cas, il devra faire une réallocation. C'est plus facile à lire, cependant. Notez que ce n'est pas le cas pour une série de concaténations. Ainsi, par exemple, cela en utilise unStringBuilder
:Cela se traduit en gros par:
Donc ce n'est pas grave, bien que le constructeur par défaut et les réallocations ultérieures ne soient pas idéales, les chances sont que c'est assez bon - et la concaténation est beaucoup plus lisible.
Mais ce n'est que pour une seule expression. Plusieurs
StringBuilder
s sont utilisés pour cela:Cela finit par devenir quelque chose comme ça:
... ce qui est assez moche.
Il est important de se rappeler, cependant, que dans tous les cas, sauf dans de très rares cas, cela n'a pas d'importance et que la lisibilité (qui améliore la maintenabilité) est préférable, sauf pour un problème de performance spécifique.
la source
x + y + z
expression plutôt queStringBuilder
si j'avais de bonnes raisons de soupçonner que ce serait un problème important.StringBuilder sql = new StringBuilder(" XXX); sql.append("nndmn");...
. Dessql.append
lignes similaires sont d'environ 60 lignes. Est-ce bien?StringBuilder
sera initialement alloué assez de place pour la chaîne que vous avez passée au constructeur plus 16 caractères. Donc, si vous ajoutez plus de 16 caractères (j'ose dire que vous l'êtes, s'il y en a 60!), LeStringBuilder
devra réallouer au moins une fois et peut-être plusieurs fois. Si vous avez une idée raisonnable de la taille du résultat final (disons, 400 caractères), il est préférable de fairesql = new StringBuilder(400);
(ou quoi que ce soit) puis de faire leappend
s.StringBuilder
qu'à l'avance économisera environ huit réallocations de mémoire (en supposant que la chaîne initiale était d'environ 10 caractères, le SB aurait été de 26 au départ, puis doublé à 52, puis 104, 208, 416, 832, 1664, 3328 et enfin 6656). Seulement significatif s'il s'agit d'un hotspot, mais quand même, si vous le savez à l'avance ... :-)Lorsque vous avez déjà tous les "morceaux" que vous souhaitez ajouter, il est inutile d'utiliser
StringBuilder
du tout. L'utilisationStringBuilder
et la concaténation de chaînes dans le même appel que votre exemple de code est encore pire.Ce serait mieux:
Dans ce cas, la concaténation de chaînes se produit de toute façon au moment de la compilation , c'est donc l'équivalent du plus simple:
L'utilisation
new StringBuilder().append("select id1, ").append(" id2 ")....toString()
réduira en fait les performances dans ce cas, car elle force la concaténation à être effectuée au moment de l'exécution , plutôt qu'au moment de la compilation . Oups.Si le code réel construit une requête SQL en incluant des valeurs dans la requête, il s'agit d'un autre problème distinct , à savoir que vous devez utiliser des requêtes paramétrées, en spécifiant les valeurs dans les paramètres plutôt que dans le SQL.
J'ai un article sur
String
/ surStringBuffer
lequel j'ai écrit il y a quelque temps - avant d'StringBuilder
arriver. Les principes s'appliquent cependantStringBuilder
de la même manière.la source
[[Il y a de bonnes réponses ici, mais je trouve qu'elles manquent encore d'un peu d'informations. ]]
Donc, comme vous le faites remarquer, l'exemple que vous donnez est simpliste mais analysons-le quand même. Ce qui se passe ici, c'est que le compilateur fait réellement le
+
travail ici car ce"select id1, " + " id2 " + " from " + " table"
sont toutes des constantes. Donc, cela se transforme en:Dans ce cas, évidemment, il ne sert à rien d'utiliser
StringBuilder
. Vous pourriez aussi bien faire:Cependant, même si vous ajoutiez des champs ou d'autres non-constantes, le compilateur utiliserait un interne
StringBuilder
- vous n'avez pas besoin d'en définir un:Sous les couvertures, cela se transforme en code qui équivaut à peu près à:
Vraiment, le seul moment où vous devez utiliser
StringBuilder
directement est lorsque vous avez du code conditionnel. Par exemple, un code qui ressemble à ce qui suit est désespéré pour unStringBuilder
:Le
+
dans la première ligne utilise uneStringBuilder
instance. Ensuite,+=
utilise une autreStringBuilder
instance. Il est plus efficace de faire:Une autre fois que j'utilise a,
StringBuilder
c'est lorsque je construis une chaîne à partir d'un certain nombre d'appels de méthode. Ensuite, je peux créer des méthodes qui prennent unStringBuilder
argument:Lorsque vous utilisez a
StringBuilder
, vous devez surveiller toute utilisation de+
en même temps:Cela
+
entraînera laStringBuilder
création d' un autre interne . Cela devrait bien sûr être:Enfin, comme le souligne @TJrowder, vous devez toujours deviner la taille du fichier
StringBuilder
. Cela permettra d'économiser sur le nombre d'char[]
objets créés lors de l'augmentation de la taille du tampon interne.la source
Vous avez raison de supposer que l'objectif de l'utilisation du générateur de chaînes n'est pas atteint, du moins pas dans toute sa mesure.
Cependant, lorsque le compilateur voit l'expression,
"select id1, " + " id2 " + " from " + " table"
il émet du code qui crée en fait unStringBuilder
derrière la scène et y ajoute, de sorte que le résultat final n'est pas si mal après tout.Mais bien sûr, quiconque regarde ce code est tenu de penser qu'il est un peu retardé.
la source
Dans le code que vous avez publié, il n'y aurait aucun avantage, car vous utilisez à mauvais escient StringBuilder. Vous créez la même chaîne dans les deux cas. En utilisant StringBuilder, vous pouvez éviter l'
+
opération sur des chaînes en utilisant laappend
méthode. Vous devriez l'utiliser de cette façon:En Java, le type String est une séquence non modifiable de caractères, donc lorsque vous ajoutez deux chaînes, la machine virtuelle crée une nouvelle valeur String avec les deux opérandes concaténés.
StringBuilder fournit une séquence de caractères modifiables, que vous pouvez utiliser pour concater différentes valeurs ou variables sans créer de nouveaux objets String, ce qui peut parfois être plus efficace que de travailler avec des chaînes
Cela fournit des fonctionnalités utiles, comme la modification du contenu d'une séquence char passée en paramètre dans une autre méthode, ce que vous ne pouvez pas faire avec Strings.
Plus d'informations sur http://docs.oracle.com/javase/tutorial/java/data/buffers.html
la source
+
, qui sera de toute façon converti dans le même code.StringBuilder
est utile lorsque vous ne pouvez pas effectuer toute la concaténation dans une seule expression, mais pas dans ce cas.StringBuilder
si vous deviez en utiliserreturn "select id1, " + foo + "something else" + bar;
- alors pourquoi ne pas le faire? La question ne donne aucune indication que quoi que ce soit doit passerStringBuilder
.Vous pouvez également utiliser MessageFormat aussi
la source