Во время работы с базами данных я заметил, что пишу строки запроса, и в этих строках я должен поставить несколько ограничений в предложение where из списка / массива / коллекции. Должно получиться так:
select * from customer
where customer.id in (34, 26, ..., 2);
Вы можете упростить это, сведя это к вопросу о том, что у вас есть набор строк и вы хотите создать список этих строк, разделенных запятыми, всего в одной строке.
Мой подход, который я использовал до сих пор, выглядит примерно так:
String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
if(first) {
result+=string;
first=false;
} else {
result+=","+string;
}
}
Но это как видите очень некрасиво. Вы не можете увидеть, что там происходит с первого взгляда, особенно когда построенные строки (как и каждый запрос SQL) усложняются.
Какой у вас (более) элегантный образ?
Ответы:
Примечание. Эти ответы были хорошими, когда они были написаны 11 лет назад, но теперь есть гораздо лучшие варианты сделать это более чисто в одной строке, как с использованием только встроенных классов Java, так и с использованием служебной библиотеки. См. Другие ответы ниже.
Поскольку строки неизменяемы, вы можете использовать класс StringBuilder, если собираетесь изменить String в коде.
Класс StringBuilder можно рассматривать как изменяемый объект String, который выделяет больше памяти при изменении его содержимого.
Исходное предложение в вопросе можно написать еще более четко и эффективно, если позаботиться о лишней конечной запятой :
источник
Используйте Google гуавы API «сек
join
метод:источник
Joiner
; google-collections.googlecode.com/svn/trunk/javadoc/com/google/…Я только что посмотрел на код, который сделал это сегодня. Это вариант ответа AviewAnew.
Используемый нами StringUtils (<- commons.lang 2.x или ссылка commons.lang 3.x ) взят из Apache Commons .
источник
Я пишу этот цикл следующим образом:
Не беспокойтесь о производительности sep. Задание выполняется очень быстро. Hotspot имеет тенденцию откладывать первую итерацию цикла в любом случае (поскольку ему часто приходится иметь дело с такими странностями, как нулевые и моно / биморфные проверки встраивания).
Если вы используете его много (более одного раза), поместите его в общий метод.
Есть еще один вопрос о stackoverflow, касающийся того, как вставить список идентификаторов в оператор SQL.
источник
Начиная с Java 8, вы можете использовать:
String String.join(CharSequence delimiter, CharSequence... elements)
String String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
Если вы хотите взять non-
String
s и присоединить их к aString
, вы можете использоватьCollectors.joining(CharSequence delimiter)
, например:String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));
источник
cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));
для одной переменной из вашей коллекции.stream
. Для int [] или long [] или других массивов, где значение может быть просто приведеноString
, я бы поискал решение без потоковой передачи. Собственно ищу.Я нашел идиому итератора элегантной, потому что в ней есть тест на большее количество элементов (для краткости опущен нулевой / пустой тест):
источник
Для этого есть много ручных решений, но я хотел повторить и обновить ответ Джули выше. Используйте Google Collections Joiner class .
Он обрабатывает аргументы var, итерации и массивы, а также правильно обрабатывает разделители более чем одного символа (в отличие от ответа Гиммеля). Он также будет обрабатывать нулевые значения в вашем списке, если вам это нужно.
источник
Вот невероятно общая версия, которую я построил из комбинации предыдущих предложений:
источник
доступно в Java8 api.
альтернатива (без необходимости добавлять зависимость google guava):
источник
Вы могли бы попробовать
источник
Пока это будет самое короткое решение, за исключением использования Guava или Apache Commons.
Хорошо работает со списком элементов 0,1 и n. Но вам нужно будет проверить нулевой список. Я использую это в GWT, так что мне хорошо без StringBuilder. А для коротких списков всего с парой элементов тоже нормально;)
источник
На случай, если кто-то столкнулся с этим в последнее время, я добавил простой вариант с использованием Java 8
reduce()
. Он также включает некоторые из уже упомянутых решений другими:источник
В Android вы должны использовать это:
источник
Я думаю, что это не лучшая идея создавать sql, объединяющий значения предложения where, как вы:
Откуда
valueX
берется из списка строк.Во-первых, если вы сравниваете строки, они должны быть заключены в кавычки, и это нетривиально, если строки могут содержать кавычки внутри.
Во-вторых, если значения поступают от пользователя или другой системы, то возможна атака с использованием SQL-инъекции.
Он намного более подробный, но вам следует создать такую строку:
а затем свяжите переменные с
Statement.setString(nParameter,parameterValue)
.источник
Еще один способ справиться с этой проблемой. Не самый короткий, но эффективный и выполняет свою работу.
источник
Есть некоторые сторонние библиотеки Java, которые предоставляют метод соединения строк, но вы, вероятно, не захотите начинать использовать библиотеку только для чего-то такого простого. Я бы просто создал такой вспомогательный метод, который, как мне кажется, немного лучше, чем ваша версия, он использует StringBuffer, который будет более эффективным, если вам нужно объединить много строк, и он работает с коллекцией любого типа.
Другое предложение с использованием Collection.toString () короче, но оно полагается на Collection.toString (), возвращающее строку в очень специфическом формате, на который я лично не хотел бы полагаться.
источник
Если вы используете Spring, вы можете:
(пакет org.springframework.util)
источник
Я не уверен, насколько это «изощренно», но определенно немного короче. Он будет работать с различными типами коллекций, например Set <Integer>, List <String> и т. Д.
Упражнение для читателя : измените этот метод, чтобы он правильно обрабатывал пустую / пустую коллекцию :)
источник
Что делает код уродливым, так это особая обработка первого случая. Большинство строк в этом небольшом фрагменте посвящены не выполнению рутинной работы кода, а обработке этого особого случая. И это то, что решают альтернативы, такие как gimel's, перемещая специальную обработку за пределы цикла. Есть один особый случай (ну, вы можете видеть и начало, и конец как особые случаи, но только один из них требует особой обработки), поэтому обработка его внутри цикла излишне сложна.
источник
Я только что зарегистрировал тест на свой библиотечный доллар :
это создать свободно обертку списков / массивы / строки / и т.д. , используя только один статический импорт :
$
.NB :
используя диапазоны, предыдущий список можно переписать как
$(1, 5).join(",")
источник
Преимущество выражения IN заключается в том, что если у вас есть повторяющиеся значения, это не меняет результат. Итак, просто продублируйте первый элемент и обработайте весь список. Предполагается, что в списке есть хотя бы один элемент. Если элементов нет, я бы предложил сначала проверить это, а затем вообще не выполнять SQL.
Это поможет, очевидно, в том, что он делает, и не зависит от каких-либо внешних библиотек:
источник
Хотя я думаю, что лучше всего использовать Joiner из Guava, если бы я закодировал его вручную, я считаю этот подход более элегантным, чем «первый» флаг или удаление последней запятой.
источник
если у вас есть массив, вы можете:
источник
Другой вариант, основанный на том, что я здесь вижу (с небольшими изменениями).
источник
«Методы» соединения доступны в массивах и классах, которые расширяют,
AbstractCollections
но не переопределяютtoString()
метод (как практически все коллекции вjava.util
).Например:
Это довольно странный способ, поскольку он работает только для чисел, похожих на данные SQL.
источник
StringUtils из springframeowrk: spring-core
источник
Возможно, вы сможете использовать LINQ (to SQL), и вы сможете использовать образец LINQ для динамических запросов от MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
источник
источник
источник
Токен списка = новый ArrayList (результат); окончательный строитель StringBuilder = новый StringBuilder ();
builder.toString ();
источник