Les plus sophistiqués de création séparée par des virgules des Chaînes à partir d'une Collection ou un Tableau/Liste?
Au cours de mon travail avec les bases de données, j'ai remarqué que j'écris des chaînes de requête et dans ce chaînes, je dois mettre plusieurs restrictions dans la clause where à partir d'une liste ou un tableau ou d'une collection. Devrait ressembler à ceci:
select * from customer
where customer.id in (34, 26, ..., 2);
Vous pouvez simplifier en réduisant les ce à la question que vous avez collection de chaînes et que vous voulez créer une liste séparée par des virgules de cette chaînes en une seule chaîne.
Mon approche que j'ai utilisé jusqu'à présent est quelque chose comme ça:
String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
if(first) {
result+=string;
first=false;
} else {
result+=","+string;
}
}
Mais c'est comme vous pouvez le voir très moche. Vous ne pouvez pas voir ce qui s'y passe sur le premier coup d'oeil, en particulier lors de la construction des chaînes de caractères (comme à chaque requête SQL) se complique.
Qu'est-ce que votre (plus) de manière élégante?
- Sans doute le SQL ci-dessus doit effectivement ressembler à ceci: select * from client where client.id in (34, 26, 2);
- Il est une partie délicate, lorsque les éléments de la liste (chaînes de caractères) eux-mêmes contiennent des virgules ou des guillemets et ils doivent être échappés avec des guillemets. Si je n'ai pas manqué de rien, les exemples ci-dessus ne considère pas cela et je déteste l'idée de passer en boucle sur tous les textes et de recherche pour les virgules.. pensez-vous il ya une meilleure façon de résoudre ce problème?
- cochez cette réponse hors... stackoverflow.com/a/15815631/728610
- Avez-vous déjà vérifié stackoverflow.com/questions/10850753/... ?
- Cela devrait le faire. stackoverflow.com/a/15815631/3157062
Vous devez vous connecter pour publier un commentaire.
Depuis les chaînes sont immuables, vous pouvez utiliser la classe StringBuilder si vous allez modifier la Chaîne de caractères dans le code.
La classe StringBuilder peut être vu comme une mutable objet String qui alloue plus de mémoire lorsque son contenu est modifié.
La proposition initiale de la question peut être écrit de manière encore plus clairement et efficacement, en prenant soin de l' redondant virgule:
StringBuilder
ici à tous. Vous pouvez utiliser la normaleString
et remplacer l'appender méthode par+=
.Utiliser le Google API de Goyave's
join
méthode:Joiner
; google-collections.googlecode.com/svn/trunk/javadoc/com/google/...J'ai juste regardé le code qui fait cela aujourd'hui. C'est une variation sur AviewAnew de réponse.
La StringUtils ( <-- commons.lang 2.x, ou commons.lang 3.x lien), nous avons utilisé est de Apache Commons.
La façon dont j'écris que la boucle est:
Ne vous inquiétez pas au sujet de la performance de la sep. La cession est très rapide. Hotspot a tendance à se décoller de la première itération d'une boucle de toute façon (comme il a souvent à faire face à des bizarreries comme nulle et mono/bimorphe inline contrôles).
Si vous l'utilisez beaucoup (plus d'une fois), le mettre dans une méthode partagée.
Il y a une autre question sur stackoverflow comment insérer une liste d'id dans la requête SQL.
Depuis Java 8, vous pouvez utiliser:
String String.join(CharSequence délimiteur, CharSequence... éléments)
String String.join(CharSequence délimiteur, Itérable<? s'étend CharSequence> éléments)
Si vous voulez prendre le non-
String
s et de les associer à unString
, vous pouvez utiliserCollectionneurs.l'adhésion(CharSequence délimiteur)
, par exemple:String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));
cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));
à une seule variable à partir de votre collection.stream
. Pour int[] ou long[] ou d'autres tableaux où la valeur peut être simplement jeté àString
, j'aurais l'air pour une non-solution de streaming. En fait, je suis à la recherche.J'ai trouvé l'itérateur d'un langage élégant, car il a un test pour plus d'éléments (omis null/vide de test pour des raisons de concision):
Il y a beaucoup de manuel des solutions, mais je voulais réitérer et mise à jour de Julie, la réponse ci-dessus. Utilisation google collections Menuisier classe.
Il gère var args, iterables et des tableaux et gère correctement les séparateurs de plus d'un char (contrairement à gimmel de réponse). Il permettra également de gérer les valeurs null dans votre liste, si vous en avez besoin pour.
Voici un incroyablement version générique que j'ai construit à partir d'une combinaison de la précédente suggestions:
disponibles dans la Java8 api.
alternative (sans avoir besoin d'ajouter un google goyave dépendance):
Vous pouvez essayer de
Ce sera le plus court de solution jusqu'à présent, à l'exception de l'aide à la Goyave ou Apache Commons
Bon 0,1 et n élément de la liste. Mais vous aurez besoin de vérifier la nullité de la liste.
- Je l'utiliser dans GWT, donc je suis bon sans StringBuilder là. Et pour de courtes listes avec juste quelques éléments de son ok aussi d'ailleurs 😉
Au cas où quelqu'un tombé sur ceci dans des temps plus récents, j'ai ajouté une simple variation à l'aide de Java 8
reduce()
. Elle inclut également des solutions par d'autres:Dans Android, vous devez utiliser cette:
Je pense que c'est pas une bonne idée contruct le sql de la concaténation de la clause where des valeurs comme vous le faites :
Où
valueX
provient d'une liste de Chaînes de caractères.Tout d'abord, si vous êtes de la comparaison de Chaînes, ils doivent être cités, ce qu'il n'est pas trivial si les Chaînes pourraient avoir un devis à l'intérieur.
Deuxièmement, si les valeurs provient de l'utilisateur,ou d'un autre système, puis une attaque par injection SQL est possible.
C'est beaucoup plus détaillé, mais ce que vous devez faire est de créer une Chaîne comme celle-ci:
et ensuite lier les variables avec
Statement.setString(nParameter,parameterValue)
.Juste une autre méthode pour faire face à ce problème. Pas le plus court, mais il est efficace et fait le travail.
Il y a quelques Java tiers des bibliothèques qui fournissent une chaîne de rejoindre méthode, mais vous ne voulez probablement pas à démarrer à l'aide d'une bibliothèque juste pour quelque chose de simple comme ça. Je voudrais juste créer une méthode d'aide de ce genre, qui je pense est un peu mieux que votre version, Il utilise StringBuffer, qui sera plus efficace si vous avez besoin de joindre de nombreuses chaînes, et il fonctionne sur une collection de n'importe quel type.
Une autre suggestion avec l'aide de la Collection.toString() est plus courte, mais qui s'appuie sur la Collecte.toString() pour retourner une chaîne de caractères dans un modèle très précis, que je serais personnellement pas besoin de s'appuyer sur.
Si vous utilisez le Printemps, vous pouvez faire:
(package org.springframework.util)
Je ne suis pas sûr de savoir comment "sophistiqué" c'est, mais c'est certainement un peu plus courte. Il fonctionne avec différents types de collection par exemple Set<Integer>, List<String>, etc.
Exercice pour le lecteur: modifier cette méthode afin qu'il gère correctement un null/vide, collection 🙂
Ce qui rend le code moches, c'est le spécial de manutention pour le premier cas. La plupart des lignes de ce petit extrait sont consacrés, de ne pas faire le code de la routine de travail, mais au traitement de ce cas particulier. Et c'est ce que des solutions de rechange comme les cascades de gimel résoudre, en déplaçant le traitement spécial en dehors de la boucle. Il y a un cas spécial (eh bien, vous pourriez voir à la fois début et fin comme un cas spécial, mais un seul d'entre eux doit être traitée spécialement), donc de gérer à l'intérieur de la boucle est inutilement compliqué.
J'ai juste vérifié-lors d'un test de ma bibliothèque dollar:
la création d'un fluide wrapper autour de listes/tableaux/cordes/etc à l'aide de un seul statique d'importation:
$
.NB:
à l'aide de plages de la liste précédente peut être ré-écrits comme
$(1, 5).join(",")
La bonne chose à propos de l'expression, c'est que si vous avez des valeurs répétées, il ne change pas le résultat. Donc, il suffit de dupliquer le premier élément et le processus de l'ensemble de la liste. Cela suppose qu'il existe au moins un élément dans la liste. Si il n'y a pas d'éléments, je vous suggère de vérifier que la première, puis de la non-exécution de SQL à tous.
Cela fera l'affaire, il est évident que dans ce qu'il fait et ne repose pas sur toutes les bibliothèques externes:
Alors que je pense que votre meilleur pari est d'utiliser Menuisier de Goyave, si je code à la main je trouve cette approche plus élégant que le "premier" drapeau ou hacher la dernière virgule off.
si vous avez un tableau que vous pouvez faire:
Une autre option, en fonction de ce que je vois ici (avec de légères modifications).
Rejoindre les "méthodes" sont disponibles dans les Tableaux et les classes qui étendent
AbstractCollections
mais ne modifie pastoString()
méthode (à l'instar de presque toutes les collections dansjava.util
).Par exemple:
C'est assez bizarre de chemin depuis il ne fonctionne que pour les numéros de semblables données SQL sage.
Vous pouvez être en mesure d'utiliser LINQ (SQL), et vous pouvez être en mesure de faire usage de la Dynamique de Requête LINQ échantillon de MME http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Liste de token=new ArrayList(result);
final StringBuilder builder = new StringBuilder();
builder.toString();
Il existe un moyen facile. Vous pouvez obtenir votre résultat dans une seule ligne.
D'obtenir des idée de vérifier le code ci-dessous
Le Plus simple de la façon de android pour convertir Liste séparée par des Virgules de la Chaîne est En utilisant les
android.text.TextUtils