Au cours de mon travail avec les bases de données, j'ai remarqué que j'écrivais des chaînes de requête et que dans ces chaînes, je dois mettre plusieurs restrictions dans la clause where d'une liste / tableau / collection. Devrait ressembler à ceci:
select * from customer
where customer.id in (34, 26, ..., 2);
Vous pouvez simplifier cela en réduisant cela à la question que vous avez une collection de chaînes et que vous souhaitez créer une liste séparée par des virgules de ces chaînes dans une seule chaîne.
Mon approche que j'ai utilisée 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 au premier regard, en particulier lorsque les chaînes construites (comme chaque requête SQL) se compliquent.
Quelle est votre (plus) élégante manière?
Réponses:
Remarque: cette réponse était bonne lorsqu'elle a été écrite il y a 11 ans, mais il existe maintenant de bien meilleures options pour le faire plus proprement sur une seule ligne, à la fois en utilisant uniquement les classes intégrées Java ou en utilisant une bibliothèque d'utilitaires. Voir les autres réponses ci-dessous.
Étant donné que les chaînes sont immuables, vous pouvez utiliser la classe StringBuilder si vous allez modifier la chaîne dans le code.
La classe StringBuilder peut être considérée comme un objet String mutable qui alloue plus de mémoire lorsque son contenu est modifié.
La suggestion originale dans la question peut être écrite encore plus clairement et plus efficacement, en prenant soin de la virgule de fin redondante :
la source
Utilisez l' API Google goyave de »
join
méthode:la source
Joiner
; google-collections.googlecode.com/svn/trunk/javadoc/com/google/…Je viens de regarder le code qui a fait cela aujourd'hui. Ceci est une variante de la réponse d'AviewAnew.
Le StringUtils (<- commons.lang 2.x ou lien commons.lang 3.x ) que nous avons utilisé provient d' Apache Commons .
la source
La façon dont j'écris cette boucle est:
Ne vous inquiétez pas des performances de sep. Une mission est très rapide. Le point d'accès a tendance à décoller de toute façon la première itération d'une boucle (car il doit souvent faire face à des bizarreries telles que les vérifications d'inlining nulles et mono / bimorphes).
Si vous l'utilisez beaucoup (plus d'une fois), placez-le dans une méthode partagée.
Il y a une autre question sur stackoverflow traitant de la façon d'insérer une liste d'identifiants dans une instruction SQL.
la source
Depuis Java 8, vous pouvez utiliser:
String String.join(CharSequence delimiter, CharSequence... elements)
String String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
Si vous voulez prendre des non-
String
s et les joindre à unString
, vous pouvez utiliserCollectors.joining(CharSequence delimiter)
, par exemple:String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));
la source
cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));
pour une seule variable de votre collection.stream
. Pour les tableaux int [] ou long [] ou d'autres où la valeur peut simplement être castéeString
, je chercherais une solution sans streaming. En fait je cherche.J'ai trouvé l'idiome de l'itérateur élégant, car il a un test pour plus d'éléments (test nul / vide omis pour la brièveté):
la source
Il y a beaucoup de solutions manuelles à cela, mais je voulais réitérer et mettre à jour la réponse de Julie ci-dessus. Utilisez la classe Joiner de google collections .
Il gère les var args, les itérables et les tableaux et gère correctement les séparateurs de plus d'un caractère (contrairement à la réponse de gimmel). Il gérera également les valeurs nulles de votre liste si vous en avez besoin.
la source
Voici une version incroyablement générique que j'ai construite à partir d'une combinaison des suggestions précédentes:
la source
disponible dans l'API Java8.
alternative à (sans avoir besoin d'ajouter une dépendance google guava):
la source
Tu pourrais essayer
la source
Ce sera la solution la plus courte à ce jour, sauf en utilisant Guava ou Apache Commons
Bon avec une liste d'éléments 0,1 et n. Mais vous devrez vérifier la liste nulle. Je l'utilise dans GWT, donc je suis bon sans StringBuilder là-bas. Et pour les listes courtes avec juste quelques éléments, ça va aussi ailleurs;)
la source
Au cas où quelqu'un trébucherait dessus plus récemment, j'ai ajouté une simple variation utilisant Java 8
reduce()
. Il comprend également certaines des solutions déjà mentionnées par d'autres:la source
Dans Android, vous devez utiliser ceci:
la source
Je pense que ce n'est pas une bonne idée de construire le SQL concaténant les valeurs de la clause where comme vous le faites:
D'où
valueX
vient une liste de chaînes.Premièrement, si vous comparez des chaînes, elles doivent être entre guillemets, et ce n'est pas anodin si les chaînes peuvent avoir un guillemet à l'intérieur.
Deuxièmement, si les valeurs proviennent de l'utilisateur ou d'un autre système, une attaque par injection SQL est possible.
C'est beaucoup plus détaillé, mais ce que vous devriez faire est de créer une chaîne comme celle-ci:
puis liez les variables avec
Statement.setString(nParameter,parameterValue)
.la source
Juste une autre méthode pour résoudre ce problème. Pas le plus court, mais il est efficace et fait le travail.
la source
Il existe des bibliothèques Java tierces qui fournissent une méthode de jointure de chaîne, mais vous ne voulez probablement pas commencer à utiliser une bibliothèque juste pour quelque chose de simple comme ça. Je voudrais simplement créer une méthode d'aide comme celle-ci, qui je pense est un peu meilleure que votre version, elle utilise StringBuffer, qui sera plus efficace si vous avez besoin de joindre plusieurs chaînes, et cela fonctionne sur une collection de n'importe quel type.
Une autre suggestion avec l'utilisation de Collection.toString () est plus courte, mais cela repose sur Collection.toString () renvoyant une chaîne dans un format très spécifique, sur lequel je ne voudrais personnellement pas me fier.
la source
Si vous utilisez Spring, vous pouvez faire:
(package org.springframework.util)
la source
Je ne sais pas à quel point c'est "sophistiqué", mais c'est certainement un peu plus court. Il fonctionnera avec différents types de collections, par exemple Set <Integer>, List <String>, etc.
Exercice pour le lecteur : modifiez cette méthode pour qu'elle gère correctement une collection nulle / vide :)
la source
Ce qui rend le code moche, c'est la manipulation spéciale pour le premier cas. La plupart des lignes de ce petit extrait de code sont consacrées, non pas au travail de routine du code, mais à la gestion de ce cas particulier. Et c'est ce que résolvent des alternatives comme celle de gimel, en déplaçant la manipulation spéciale en dehors de la boucle. Il y a un cas particulier (enfin, vous pouvez voir à la fois le début et la fin comme des cas spéciaux - mais un seul d'entre eux doit être traité spécialement), donc le gérer à l'intérieur de la boucle est inutilement compliqué.
la source
Je viens de faire un test pour mon dollar de bibliothèque :
il créer un wrapper autour des listes couramment / tableaux / chaînes / etc en utilisant une seule importation statique :
$
.NB :
en utilisant des plages, la liste précédente peut être réécrite comme
$(1, 5).join(",")
la source
L'avantage de l'expression IN est que si vous avez des valeurs répétées, cela ne change pas le résultat. Alors, dupliquez simplement le premier élément et traitez la liste entière. Cela suppose qu'il y a au moins un élément dans la liste. S'il n'y a pas d'éléments, je suggérerais de vérifier cela d'abord, puis de ne pas exécuter du tout le SQL.
Cela fera l'affaire, est évident dans ce qu'il fait et ne repose sur aucune bibliothèque externe:
la source
Bien que je pense que votre meilleur pari est d'utiliser Joiner de Guava, si je devais le coder à la main, je trouve cette approche plus élégante que le «premier» drapeau ou couper la dernière virgule.
la source
si vous avez un tableau, vous pouvez faire:
la source
Une autre option, basée sur ce que je vois ici (avec de légères modifications).
la source
Les 'méthodes' de jointure sont disponibles dans les tableaux et les classes qui s'étendent
AbstractCollections
mais ne remplacent pas latoString()
méthode (comme pratiquement toutes les collections dansjava.util
).Par exemple:
C'est une manière assez étrange car cela ne fonctionne que pour les nombres de même que les données SQL.
la source
StringUtils de springframeowrk: spring-core
la source
Vous pourrez peut-être utiliser LINQ (vers SQL), et vous pourrez peut-être utiliser l'exemple Dynamic Query LINQ de MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
la source
la source
la source
Jeton de liste = new ArrayList (résultat); constructeur final StringBuilder = nouveau StringBuilder ();
builder.toString ();
la source