Durante mi trabajo con bases de datos, noté que escribo cadenas de consulta y en estas cadenas tengo que poner varias restricciones en la cláusula where de una lista / matriz / colección. Debería verse así:
select * from customer
where customer.id in (34, 26, ..., 2);
Puede simplificar esto reduciendo esto a la pregunta de que tiene una colección de cadenas y desea crear una lista separada por comas de estas cadenas en una sola cadena.
Mi enfoque que he usado hasta ahora es algo así:
String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
if(first) {
result+=string;
first=false;
} else {
result+=","+string;
}
}
Pero esto es como puede ver muy feo. No puede ver lo que sucede allí a primera vista, especialmente cuando las cadenas construidas (como todas las consultas SQL) se vuelven complicadas.
¿Cuál es tu forma (más) elegante?
Respuestas:
Nota: Esta respuesta era buena cuando se escribió hace 11 años, pero ahora hay opciones mucho mejores para hacer esto de manera más limpia en una sola línea, tanto usando solo clases integradas de Java como usando una biblioteca de utilidades. Vea otras respuestas a continuación.
Dado que las cadenas son inmutables, es posible que desee utilizar la clase StringBuilder si va a alterar la cadena en el código.
La clase StringBuilder puede verse como un objeto String mutable que asigna más memoria cuando se modifica su contenido.
La sugerencia original en la pregunta se puede escribir aún más clara y eficientemente, cuidando la coma final redundante :
fuente
Utilizar el Google guayaba API 's
join
método:fuente
Joiner
; google-collections.googlecode.com/svn/trunk/javadoc/com/google/…Solo miré el código que hizo esto hoy. Esta es una variación de la respuesta de AviewAnew.
El StringUtils (<- commons.lang 2.x, o el enlace commons.lang 3.x ) que usamos es de Apache Commons .
fuente
La forma en que escribo ese bucle es:
No se preocupe por el rendimiento de sep. Una tarea es muy rápida. Hotspot tiende a desprenderse de la primera iteración de un bucle de todos modos (ya que a menudo tiene que lidiar con rarezas como comprobaciones de alineación nula y mono / bimórfica).
Si lo usa mucho (más de una vez), colóquelo en un método compartido.
Hay otra pregunta sobre stackoverflow que trata sobre cómo insertar una lista de identificadores en una declaración SQL.
fuente
Desde Java 8, puede usar:
String String.join(CharSequence delimiter, CharSequence... elements)
String String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
Si desea tomar non-
String
s y unirlos a aString
, puede usarCollectors.joining(CharSequence delimiter)
, por ejemplo:String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));
fuente
cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));
para una sola variable de su colección.stream
. Para int [] o long [] u otras matrices en las que el valor simplemente se puede convertirString
, buscaría una solución que no sea de transmisión. De hecho estoy mirando.Encontré el lenguaje del iterador elegante, porque tiene una prueba para más elementos (prueba nula / vacía omitida por brevedad):
fuente
Hay muchas soluciones manuales para esto, pero quería reiterar y actualizar la respuesta de Julie anterior. Utilice la clase Joiner de colecciones de Google .
Maneja var args, iterables y matrices y maneja adecuadamente los separadores de más de un char (a diferencia de la respuesta de gimmel). También manejará valores nulos en su lista si lo necesita.
fuente
Aquí hay una versión increíblemente genérica que he creado a partir de una combinación de las sugerencias anteriores:
fuente
disponible en la api de Java8.
alternativa a (sin la necesidad de agregar una dependencia de guayaba de google):
fuente
Tu podrías intentar
fuente
Esta será la solución más corta hasta ahora, excepto el uso de Guava o Apache Commons.
Bueno con 0,1 y n lista de elementos. Pero deberá verificar la lista nula. Yo uso esto en GWT, así que estoy bien sin StringBuilder allí. Y para listas cortas con solo un par de elementos, también está bien en otros lugares;)
fuente
En caso de que alguien haya tropezado con esto en tiempos más recientes, he agregado una variación simple usando Java 8
reduce()
. También incluye algunas de las soluciones ya mencionadas por otros:fuente
En Android deberías usar esto:
fuente
Creo que no es una buena idea construir el sql concatenando los valores de la cláusula where como lo estás haciendo:
De dónde
valueX
viene una lista de Strings.Primero, si está comparando cadenas, deben estar entre comillas, y esto no es trivial si las cadenas pudieran tener una cita dentro.
En segundo lugar, si los valores provienen del usuario u otro sistema, entonces es posible un ataque de inyección SQL.
Es mucho más detallado, pero lo que debes hacer es crear una cadena como esta:
y luego unir las variables con
Statement.setString(nParameter,parameterValue)
.fuente
Solo otro método para lidiar con este problema. No es el más corto, pero es eficiente y hace el trabajo.
fuente
Hay algunas bibliotecas Java de terceros que proporcionan el método de unión de cadenas, pero probablemente no desee comenzar a usar una biblioteca solo para algo tan simple como eso. Simplemente crearía un método auxiliar como este, que creo que es un poco mejor que su versión. Utiliza StringBuffer, que será más eficiente si necesita unir muchas cadenas, y funciona en una colección de cualquier tipo.
Otra sugerencia con el uso de Collection.toString () es más corta, pero se basa en Collection.toString () que devuelve una cadena en un formato muy específico, en el que personalmente no querría confiar.
fuente
Si usa Spring, puede hacer:
(paquete org.springframework.util)
fuente
No estoy seguro de cuán "sofisticado" es esto, pero ciertamente es un poco más corto. Funcionará con varios tipos diferentes de colección, por ejemplo, Set <Integer>, List <String>, etc.
Ejercicio para el lector : modifique este método para que maneje correctamente una colección nula / vacía :)
fuente
Lo que hace que el código sea feo es el manejo especial para el primer caso. La mayoría de las líneas de este pequeño fragmento están dedicadas, no a realizar el trabajo de rutina del código, sino a manejar ese caso especial. Y eso es lo que resuelven alternativas como la de Gimel, al mover el manejo especial fuera del bucle. Hay un caso especial (bueno, podría ver el inicio y el final como casos especiales, pero solo uno de ellos debe tratarse de manera especial), por lo que manejarlo dentro del ciclo es innecesariamente complicado.
fuente
Acabo de registrar una prueba por el dólar de mi biblioteca :
es crear una envoltura alrededor de fluidez listas / arreglos / cuerdas / etc usando una sola importación estática :
$
.NB :
usando rangos, la lista anterior se puede reescribir como
$(1, 5).join(",")
fuente
Lo bueno de la expresión IN es que si tiene valores repetidos, no cambia el resultado. Entonces, simplemente duplique el primer elemento y procese la lista completa. Esto supone que hay al menos un elemento en la lista. Si no hay elementos, sugeriría verificarlo primero y luego no ejecutar el SQL en absoluto.
Esto hará el truco, es obvio en lo que está haciendo y no depende de ninguna biblioteca externa:
fuente
Si bien creo que su mejor opción es usar Joiner de Guava, si tuviera que codificarlo a mano, este enfoque me parece más elegante que la 'primera' bandera o cortar la última coma.
fuente
si tiene una matriz, puede hacer:
fuente
Otra opción, basada en lo que veo aquí (con ligeras modificaciones).
fuente
Los 'métodos' de unión están disponibles en Arrays y las clases que se extienden
AbstractCollections
pero no anulan eltoString()
método (como prácticamente todas las coleccionesjava.util
).Por ejemplo:
Esa es una forma bastante extraña, ya que solo funciona para números similares a datos SQL.
fuente
StringUtils de springframeowrk: spring-core
fuente
Es posible que pueda utilizar LINQ (to SQL) y puede utilizar el ejemplo de consulta dinámica LINQ de MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
fuente
fuente
fuente
Token de lista = new ArrayList (resultado); constructor final de StringBuilder = new StringBuilder ();
constructor.toString ();
fuente