Самый сложный способ создания разделенных запятыми строк из коллекции / массива / списка? - PullRequest
97 голосов
/ 15 октября 2008

Во время моей работы с базами данных я заметил, что я пишу строки запросов, и в эти строки я должен наложить несколько ограничений в предложении 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-запрос) усложняется.

Каков ваш (более) элегантный способ?

Ответы [ 31 ]

87 голосов
/ 15 октября 2008

Используйте Google Guava API join метод:

Joiner.on(",").join(collectionOfStrings);
85 голосов
/ 15 октября 2008

Поскольку строки неизменяемы, вы можете использовать класс StringBuilder, если собираетесь изменить строку в коде.

Класс StringBuilder можно рассматривать как изменяемый объект String, который выделяет больше памяти при изменении его содержимого.

Исходное предложение в вопросе может быть написано еще более четко и эффективно, если позаботиться о избыточной запятой :

    StringBuilder result = new StringBuilder();
    for(String string : collectionOfStrings) {
        result.append(string);
        result.append(",");
    }
    return result.length() > 0 ? result.substring(0, result.length() - 1): "";
73 голосов
/ 15 октября 2008

Я только что посмотрел на код, который сделал это сегодня. Это вариант ответа AviewAnew.

collectionOfStrings = /* source string collection */;
String csList = StringUtils.join(collectionOfStrings.toArray(), ",");

Использованная нами StringUtils (<- commons.lang 2.x или <a href="http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#join(char[],%20char)" rel="noreferrer"> commons.lang 3.x ) взята из Apache Commons .

46 голосов
/ 15 октября 2008

Как я пишу этот цикл:

StringBuilder buff = new StringBuilder();
String sep = "";
for (String str : strs) {
    buff.append(sep);
    buff.append(str);
    sep = ",";
}
return buff.toString();

Не беспокойтесь о производительности сеп. Назначение очень быстро. Hotspot в любом случае имеет тенденцию отслаивать первую итерацию цикла (так как он часто сталкивается с такими странностями, как проверки с нулевым и моно / биморфным встраиванием).

Если вы используете его многократно (более одного раза), поместите его в общий метод.

Существует еще один вопрос о стеке потока, касающийся того, как вставить список идентификаторов в оператор SQL.

40 голосов
/ 20 июня 2015

Начиная с Java 8, вы можете использовать:

11 голосов
/ 16 октября 2008

Мне показалось, что итератор идиома элегантен, потому что в нем есть тест для большего количества элементов (пропущенный тест null / empty для краткости):

public static String convert(List<String> list) {
    String res = "";
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        res += iterator.next() + (iterator.hasNext() ? "," : "");
    }
    return res;
}
8 голосов
/ 23 июля 2009

Существует множество ручных решений, но я хотел повторить и обновить ответ Джулии выше. Используйте коллекции Google. Класс столяра .

.
Joiner.on(", ").join(34, 26, ..., 2)

Он обрабатывает аргументы, итерации и массивы var и правильно обрабатывает разделители более чем одного символа (в отличие от ответа gimmel) Он также будет обрабатывать нулевые значения в вашем списке, если вам это нужно.

7 голосов
/ 07 октября 2011

Вот невероятно общая версия, которую я построил из комбинации предыдущих предложений:

public static <T> String buildCommaSeparatedString(Collection<T> values) {
    if (values==null || values.isEmpty()) return "";
    StringBuilder result = new StringBuilder();
    for (T val : values) {
        result.append(val);
        result.append(",");
    }
    return result.substring(0, result.length() - 1);
}
7 голосов
/ 16 декабря 2014
String.join(", ", collectionOfStrings)

доступно в API Java8.

альтернатива (без необходимости добавления зависимости от гуавы google):

Joiner.on(",").join(collectionOfStrings);
5 голосов
/ 02 июня 2009

Вы можете попробовать

List collections = Arrays.asList(34, 26, "...", 2);
String asString = collection.toString();
// justValues = "34, 26, ..., 2"
String justValues = asString.substring(1, asString.length()-1);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...