Durante meu trabalho com bancos de dados, percebi que escrevo strings de consulta e, nessas strings, tenho que colocar várias restrições na cláusula where de uma lista / array / coleção. Deve ser assim:
select * from customer
where customer.id in (34, 26, ..., 2);
Você pode simplificar isso, reduzindo isso à questão de que você tem uma coleção de strings e deseja criar uma lista separada por vírgulas dessas strings em apenas uma string.
Minha abordagem que usei até agora é mais ou menos assim:
String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
if(first) {
result+=string;
first=false;
} else {
result+=","+string;
}
}
Mas isso é como você pode ver muito feio. Você não pode ver o que acontece lá à primeira vista, especialmente quando as strings construídas (como toda consulta SQL) estão ficando complicadas.
Qual é o seu jeito (mais) elegante?
Respostas:
Nota: Esta resposta era boa quando foi escrita 11 anos atrás, mas agora existem opções muito melhores para fazer isso de forma mais limpa em uma única linha, usando apenas classes integradas do Java ou usando uma biblioteca de utilitários. Veja outras respostas abaixo.
Como as strings são imutáveis, você pode usar a classe StringBuilder se for alterar a String no código.
A classe StringBuilder pode ser vista como um objeto String mutável que aloca mais memória quando seu conteúdo é alterado.
A sugestão original na pergunta pode ser escrita de forma ainda mais clara e eficiente, cuidando da vírgula final redundante :
fonte
Use o Google Guava API 's
join
método:fonte
Joiner
; google-collections.googlecode.com/svn/trunk/javadoc/com/google/…Acabei de ver o código que fez isso hoje. Esta é uma variação da resposta de AviewAnew.
O StringUtils (<- commons.lang 2.x ou link commons.lang 3.x ) que usamos é do Apache Commons .
fonte
A maneira como escrevo esse loop é:
Não se preocupe com o desempenho do sep. Uma tarefa é muito rápida. O ponto de acesso tende a descascar a primeira iteração de um loop de qualquer maneira (já que freqüentemente tem que lidar com estranhezas, como verificações inlining nulas e mono / bimórficas).
Se você usar muito (mais de uma vez), coloque-o em um método compartilhado.
Há outra questão sobre stackoverflow que trata de como inserir uma lista de ids em uma instrução SQL.
fonte
Desde o Java 8, você pode usar:
String String.join(CharSequence delimiter, CharSequence... elements)
String String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
Se você quiser pegar não
String
-se juntá-los a umString
, você pode usarCollectors.joining(CharSequence delimiter)
, por exemplo:String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));
fonte
cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));
para uma única variável de sua coleção.stream
. Para int [] ou long [] ou outras matrizes onde o valor pode simplesmente ser convertidoString
, eu procuraria uma solução sem streaming. Na verdade, estou procurando.Achei o idioma do iterador elegante, porque ele tem um teste para mais elementos (teste nulo / vazio omitido por brevidade):
fonte
Existem muitas soluções manuais para isso, mas eu queria reiterar e atualizar a resposta de Julie acima. Use a classe Joiner das coleções do google .
Ele lida com var args, iterables e arrays e lida corretamente com separadores de mais de um char (ao contrário da resposta do gimmel). Ele também tratará valores nulos em sua lista, se necessário.
fonte
Esta é uma versão incrivelmente genérica que construí a partir de uma combinação das sugestões anteriores:
fonte
disponível na API Java8.
alternativa para (sem a necessidade de adicionar uma dependência do google goiaba):
fonte
Você poderia tentar
fonte
Esta será a solução mais curta até agora, exceto pelo uso de Guava ou Apache Commons
Bom com 0,1 en lista de elementos. Mas você precisará verificar a lista de nulos. Eu uso isso no GWT, então estou bem sem StringBuilder lá. E para listas curtas com apenas alguns elementos também está ok em outro lugar;)
fonte
Caso alguém tenha tropeçado nisso recentemente, adicionei uma variação simples usando Java 8
reduce()
. Também inclui algumas das soluções já mencionadas por outros:fonte
No Android, você deve usar isto:
fonte
Acho que não é uma boa ideia construir o sql concatenando os valores da cláusula where como você está fazendo:
De onde
valueX
vem uma lista de Strings.Primeiro, se você está comparando Strings, elas devem ser citadas, e isso não é trivial se as Strings pudessem ter uma citação dentro.
Em segundo lugar, se os valores vierem do usuário ou de outro sistema, um ataque de injeção de SQL é possível.
É muito mais detalhado, mas o que você deve fazer é criar uma String como esta:
e vincule as variáveis com
Statement.setString(nParameter,parameterValue)
.fonte
Apenas mais um método para lidar com esse problema. Não é o mais curto, mas é eficiente e faz o trabalho.
fonte
Existem algumas bibliotecas Java de terceiros que fornecem método de junção de string, mas você provavelmente não quer começar a usar uma biblioteca apenas para algo simples como isso. Eu apenas criaria um método auxiliar como este, que acho um pouco melhor do que a sua versão, ele usa StringBuffer, que será mais eficiente se você precisar juntar muitas strings, e funciona em uma coleção de qualquer tipo.
Outra sugestão com o uso de Collection.toString () é mais curta, mas depende de Collection.toString () retornar uma string em um formato muito específico, no qual eu pessoalmente não gostaria de confiar.
fonte
Se você usa Spring, pode fazer:
(pacote org.springframework.util)
fonte
Não tenho certeza de quão "sofisticado" isso é, mas certamente é um pouco mais curto. Funcionará com vários tipos diferentes de coleção, por exemplo, Set <Integer>, List <String>, etc.
Exercício para o leitor : modifique este método para que ele lide corretamente com uma coleção nula / vazia :)
fonte
O que torna o código feio é o tratamento especial para o primeiro caso. A maioria das linhas neste pequeno trecho é dedicada, não a fazer o trabalho de rotina do código, mas a lidar com esse caso especial. E é isso que alternativas como o gimel resolve, movendo o tratamento especial para fora do loop. Há um caso especial (bem, você pode ver o início e o fim como casos especiais - mas apenas um deles precisa ser tratado de maneira especial), portanto, manipulá-lo dentro do loop é desnecessariamente complicado.
fonte
Acabei de fazer o check-in de um teste para o dinheiro da minha biblioteca :
ele cria um wrapper fluente em torno de listas / matrizes / strings / etc usando apenas uma importação estática :
$
.NB :
usando intervalos, a lista anterior pode ser reescrita como
$(1, 5).join(",")
fonte
O bom da expressão IN é que, se você repetir os valores, o resultado não será alterado. Portanto, basta duplicar o primeiro item e processar toda a lista. Isso pressupõe que haja pelo menos um item na lista. Se não houver nenhum item, sugiro verificar primeiro e, em seguida, não executar o SQL.
Isso vai funcionar, é óbvio no que está fazendo e não depende de nenhuma biblioteca externa:
fonte
Embora eu ache que sua melhor aposta é usar o Joiner do Guava, se eu fosse codificá-lo manualmente, acho essa abordagem mais elegante do que o sinalizador 'primeiro' ou cortar a última vírgula.
fonte
se você tem uma matriz, pode fazer:
fonte
Outra opção, com base no que vejo aqui (com pequenas modificações).
fonte
Os 'métodos' de junção estão disponíveis em Arrays e nas classes que estendem,
AbstractCollections
mas não substituem otoString()
método (como praticamente todas as coleções emjava.util
).Por exemplo:
Essa é uma maneira bastante estranha, pois funciona apenas para números semelhantes, dados SQL.
fonte
StringUtils de springframeowrk: spring-core
fonte
Você pode usar LINQ (to SQL) e pode usar o exemplo Dynamic Query LINQ da MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
fonte
fonte
fonte
Lista de token = novo ArrayList (resultado); construtor final StringBuilder = new StringBuilder ();
builder.toString ();
fonte