Quel est le moyen le plus rapide pour concaténer deux Chaînes de caractères en Java?
Quel est le moyen le plus rapide pour concaténer deux Chaînes de caractères en Java?
je.e
String ccyPair = ccy1 + ccy2;
Je suis en utilisant cyPair
comme une clé dans une HashMap
et il est appelé dans un très boucle pour récupérer les valeurs.
Quand j'ai le profil, puis c'est le goulot d'étranglement
java.lang.StringBuilder.append(StringBuilder.java:119)
java.lang.StringBuilder.(StringBuilder.java:93)
- goulot d'étranglement dans la concaténation de chaîne? Cela voudrait dire tous les programmes java sont d'avoir des problèmes de performance. Ne pas microoptimize.
- Mais il a présenté le code, et c'est le goulot d'étranglement. Ce n'est pas de la micro-optimisation, ni l'optimisation prématurée, c'est juste de l'optimisation.
- en fait c'est l'une des questions. Les véritables enjeux de la devise génération de code dans la boucle. Il contient plusieurs allocations de mémoire+barrières +pas si vite le code de hachage (14 mul+ajouter; en supposant devise paires sont comme des "eur/usdusd/jpy"), puis d'égal à égal. À l'aide d'une holding paire w/ références pour les 2 chaînes seront beaucoup meilleure solution.
Vous devez vous connecter pour publier un commentaire.
La raison pour laquelle ces routines apparaître dans l'indice de référence est parce que c'est la façon dont le compilateur met en œuvre votre "+" sous les couvertures.
Si vous avez vraiment besoin de la concaténation de chaîne de caractères, vous devez laisser le compilateur faire sa magie avec le "+". Si vous avez besoin est la clé d'une carte de recherche, une touche de classe à tenir les deux chaînes avec adapté
equals
ethashMap
implémentations pourrait être une bonne idée car elle permet d'éviter la copie de l'étape.Beaucoup de théorie à temps pour un peu de pratique!
À l'aide de la plaine pour les boucles de 10 000 000, sur un réchauffé 64-bit Hotspot, 1.6.0_22 sur Intel Mac OS.
par exemple
Avec les énoncés suivants dans les boucles
1.33 s
1.28 s
1.92 s
0.70 s
0,0 s
Alors concat est le gagnant clair, sauf si vous avez statiques chaînes de caractères, auquel cas le compilateur aura pris soin de vous.
Je crois que la réponse a déjà été déterminé, mais je post pour partager le code.
Réponse courte, si pure concaténation est tout ce que vous cherchez, est: String.concat(...)
De sortie:
Exemple De Code:
Vous devez tester avec une Chaîne de caractères générée au moment de l'exécution (comme l'UUID.randomUUID().toString()) pas au moment de la compilation (comme "ma chaîne"). Mes résultats sont
avec cette mise en œuvre:
De la question dans le titre:
String.concat
sera généralement le moyen le plus rapide de la concaténation de deuxString
s (mais qui nenull
s). Pas de [surdimensionné] tampon intermédiaire ou d'un autre objet est impliqué. Étrangement+
sera compilé en relativement inefficace code impliquantStringBuilder
.Cependant, le corps de vous remettre en question des points à d'autres problèmes. La concaténation de chaîne afin de générer les clés pour une carte est un bon "anti-idiome". Il s'agit d'un hack et sujette à erreur. Êtes-vous sûr que la clé générée est-il unique? Il reste unique une fois votre code est maintenu pour certains, encore inconnu à l'exigence? La meilleure approche est de créer une valeur immuable de classe pour la clé. À l'aide d'un
List
et générique tuple de la classe est un mauvais hack.Pour moi concat3 méthode ci-dessous est le moyen le plus rapide après avoir fait le test sur mon windows et linux à distance de la machine:-
Même si je crois qu'concat1 performance est la JVM de la mise en œuvre et l'optimisation dépendant et peut effectuer mieux dans une future version
Je vous recommande d'essayer Thorbjørn Ravn Andersens suggestion.
Si vous avez besoin de la concaténation de Chaînes de caractères, dépend de la longueur des deux parties, il pourrait être légèrement mieux pour créer le StringBuilder exemple avec la taille requise pour éviter la réaffectation des ressources. La valeur par défaut StringBuilder constructeur se réserve 16 Caractères dans l'implémentation actuelle - au moins sur ma machine. Donc, si la concaténation de Chaîne est plus longue que l'initiale de la taille de la mémoire tampon, le StringBuilder doit réaffecter.
Essayer et nous dire ce que votre profiler a à dire à ce sujet:
Peut-être à la place de la concaténation, vous devez créer une Paire de classe?
Et utiliser ce que votre clé dans votre HashMap
Au lieu de
HashMap<String,Whatever>
utilisationHashMap<Pair<String,String>,Whatever>
Dans votre boucle serrée, au lieu de
map.get( str1 + str2 )
que vous souhaitez utilisermap.get( Pair.create(str1,str2) )
.public static void main method
pour vous paire classe de sorte qu'il peut être à portée de main pour référence ultérieureString
va aider le compilateur à lier statiquement equals et hashcode (maintenant, il va probablement revenir à inline caches bien que, pas tellement minable, mais quand même)Peut-être vous pouvez faire le tour du problème par le calcul les valeurs de hachage de deux chaînes individuellement, puis en les combinant, peut-être avec une autre fonction de hachage qui travaille sur des entiers?
Quelque chose comme:
Qui pourrait bien être plus rapide, car la concaténation de chaînes uniquement à calculer la valeur de hachage de la concaténation semble inutile.
Remarque que ci-dessus combine les deux hachages avec binaire XOR (le
^
opérateur) qui fonctionne souvent, mais vous pourriez vouloir étudier que d'autres.Ok, alors quel est votre question?
Rien à faire: si vous avez pour concaténer des chaînes de caractères le faire. C'est bien que vous profilé votre code. Maintenant, vous pouvez voir le fait que l'opérateur de concaténation de chaîne + utilise automatiquement StringBuilder apposer() la méthode, à l'aide de
ne pas vous donner de sérieux atouts.
La seule façon sérieuse afin d'optimiser votre code est probablement changer votre conception d'omettre la concaténation à tous. Mais faites-le seulement si vous en avez vraiment besoin, c'est à dire la concaténation prend part importante de temps CPU.
@Duncan McGregor réponse donne un certain nombre de référence pour un exemple particulier (tailles de chaîne d'entrée) et une version JVM. Dans ce cas, il ressemble à
String.concat()
est le gagnant par un facteur significatif. Ce résultat peut ou ne peut pas généraliser.De côté: Ce qui me surprend! J'aurais pensé que le compilateur écrivains aurait choisi d'utiliser des chaînes de caractères.concat dans les cas où il est susceptible d'être plus rapide. L'explication est dans l'évaluation de ce rapport de bug ... et qui est ancrée dans la définition de l'opérateur de concaténation de Chaîne.
(Si une Chaîne de type de l'opérande de
+
estnull
, le JLS états que la Chaîne"null"
est utilisée à sa place. Qui ne fonctionnent pas si elles le code générés + s2
commes.concat(s2)
ets
ous2
qui est arrivé à êtrenull
; vous obtiendrez des Npe. Et le cas des == null
signifie qu'une version alternative deconcat
ne résout pas le NPE problème.)Cependant, @détendre réponse m'a donné une idée pour une solution alternative qui évite la nécessité pour la concaténation de Chaîne.
Si les concaténations de
ccy1
etccy2
sont juste faites pour joindre deux touches, alors peut-être que vous pourriez obtenir une meilleure performance par la définition d'un spécial d'une table de hachage de la classe qui prend deux touches au lieu d'une. Il aurait opérations comme:L'effet serait comme un
Map<Pair<String, String>, Object>
(voir @KitsuneYMG de réponse), sauf que vous n'avez pas besoin de créerPair<String, String>
les objets chaque fois que vous voulez faire unget
ouput
. L'inconvénient est:Map
interface.Normalement, je ne recommanderais pas cela. Toutefois, si la concaténation de chaîne et la carte de recherche sont vraiment une critique goulot d'étranglement, une coutume multi-clé de la table de hachage peut vous donner une accélération significative.
System.arrayCopy
(ainsi, un char[] alloc, 2 memcpy, une chaîne alloc, cant beat que jamais), mais la plupart de tous, c'est la seule façon de créer une Chaîne w/o copie supplémentaire du char array (à compter de maintenant, retour dans la journée StringBuffer ne pas copier)s.concat(s2)
pours + s2
. Mais c'est logique; voir ci-dessus.String.valueOf(s1).contact(String.valueOf(s2))
; en fait, je l'avais jure que j'ai vu JBuilder t-il (mais il était au moins 8 ans, donc je n'avais pas jurer pour de vrai)Ici c'est la pleine mise en œuvre de linéaire de la sonde de la carte w/double des clés, une seule valeur. Il devrait dépasser java.util.HashMap bien.
Avertissement, c'est écrit dans les toutes premières heures de la journée à partir de zéro, de sorte qu'il peut contenir des bugs. N'hésitez pas à le modifier.
La solution doit battre n'importe quel emballage, concat à tout moment. Le pas de l'allocation obtenir/mettre la rend aussi rapide à des fins générales de la carte.
Espère que cela résout le problème. (Le code provient w/quelques tests simples qui sont inutiles)
Avez-vous essayé d'utiliser un Tampon de Chaîne et ensuite utiliser un profiler pour voir où est le goulot d'étranglement.Donnez-lui un essai et voir ce qui se passe.
Garder à l'esprit que si vous êtes à la concaténation des millions de chaînes, puis de la chaîne.concat sera plus susceptible de générer des millions de nouvel objet string réf. Cela aura une augmentation de l'utilisation CPU.
Selon la Spécifications de Java (et depuis la toute première version de Java), dans la section "Opérateur de Concaténation de Chaîne +", il est dit :
Donc, fondamentalement, à l'aide de la
+ operator
ouStringBuilder.append
pour les variables de base est le même.Autre chose, je sais que dans votre question, vous avez mentionné l'ajout de seulement 2 Chaînes, mais avoir à l'esprit que l'ajout de 3 ou plus de Chaînes conduise à des résultats différents :
J'ai utilisé un peu modifié @Duncan McGregor exemple. J'ai 5 méthodes de la concaténation de 2 à 6 cordes à l'aide de concat et 5 méthodes de la concaténation de 2 à 6 cordes à l'aide de StringBuilder :
J'ai obtenu ces résultats (en secondes) :
testConcatenation2stringsConcat : 0.018 |||||||||||||||| testConcatenation2stringsSB : 0.2
testConcatenation3stringsConcat : 0.35 ||||||||||||||||||| testConcatenation3stringsSB : 0.25
testConcatenation4stringsConcat : 0.5 |||||||||||||||||||||| testConcatenation4stringsSB : 0.3
testConcatenation5stringsConcat : 0.67 ||||||||||||||||||| testConcatenation5stringsSB : 0.38
testConcatenation5stringsConcat : 0.9 |||||||||||||||||||||| testConcatenation5stringsSB : 0.43
la concaténation de seulement 2 Chaînes
lentement, à l'aide de la méthode concat
sont très longues