Каков наилучший способ создать строку элементов с разделителями в Java? - PullRequest
275 голосов
/ 15 сентября 2008

Работая в приложении Java, я недавно должен был собрать список значений, разделенных запятыми, для передачи в другой веб-сервис, не зная, сколько элементов будет заранее. Лучшее, что я мог придумать, это было примерно так:

public String appendWithDelimiter( String original, String addition, String delimiter ) {
    if ( original.equals( "" ) ) {
        return addition;
    } else {
        return original + delimiter + addition;
    }
}

String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );

Я понимаю, что это не особенно эффективно, поскольку повсюду создаются строки, но я собирался сделать это для большей ясности, чем для оптимизации.

В Ruby я могу сделать что-то вроде этого, что выглядит намного элегантнее:

parameterArray = [];
parameterArray << "elementName" if condition;
parameterArray << "anotherElementName" if anotherCondition;
parameterString = parameterArray.join(",");

Но поскольку в Java нет команды соединения, я не смог найти ничего эквивалентного.

Итак, как лучше всего это сделать в Java?

Ответы [ 35 ]

4 голосов
/ 31 октября 2015

Java 8

stringCollection.stream().collect(Collectors.joining(", "));
3 голосов
/ 15 сентября 2008

Для этого вы можете использовать тип Java StringBuilder. Также есть StringBuffer, но он содержит дополнительную логику безопасности потоков, которая часто не нужна.

3 голосов
/ 26 марта 2014

И минимальный (если вы не хотите включать Apache Commons или Gauva в зависимости проекта только для объединения строк)

/**
 *
 * @param delim : String that should be kept in between the parts
 * @param parts : parts that needs to be joined
 * @return  a String that's formed by joining the parts
 */
private static final String join(String delim, String... parts) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < parts.length - 1; i++) {
        builder.append(parts[i]).append(delim);
    }
    if(parts.length > 0){
        builder.append(parts[parts.length - 1]);
    }
    return builder.toString();
}
3 голосов
/ 18 ноября 2008

Используйте StringBuilder и класс Separator

StringBuilder buf = new StringBuilder();
Separator sep = new Separator(", ");
for (String each : list) {
    buf.append(sep).append(each);
}

Разделитель переносит разделитель. Разделитель возвращается методом toString разделителя, если только при первом вызове, который возвращает пустую строку!

Исходный код для класса Separator

public class Separator {

    private boolean skipFirst;
    private final String value;

    public Separator() {
        this(", ");
    }

    public Separator(String value) {
        this.value = value;
        this.skipFirst = true;
    }

    public void reset() {
        skipFirst = true;
    }

    public String toString() {
        String sep = skipFirst ? "" : value;
        skipFirst = false;
        return sep;
    }

}
2 голосов
/ 15 сентября 2008

Почему бы не написать свой собственный метод join ()? В качестве параметров он будет принимать коллекцию Strings и разделитель String. Внутри метода переберите коллекцию и создайте результат в StringBuffer.

2 голосов
/ 16 ноября 2013

Если вы используете Eclipse Collections , вы можете использовать makeString() или appendString().

makeString() возвращает представление String, аналогичное toString().

Имеет три формы

  • makeString(start, separator, end)
  • makeString(separator) по умолчанию начало и конец пустые строки
  • makeString() по умолчанию разделитель ", " (запятая и пробел)

Пример кода:

MutableList<Integer> list = FastList.newListWith(1, 2, 3);
assertEquals("[1/2/3]", list.makeString("[", "/", "]"));
assertEquals("1/2/3", list.makeString("/"));
assertEquals("1, 2, 3", list.makeString());
assertEquals(list.toString(), list.makeString("[", ", ", "]"));

appendString() аналогично makeString(), но добавляется к Appendable (например, StringBuilder) и равно void. Он имеет те же три формы, с дополнительным первым аргументом, Присоединяемый.

MutableList<Integer> list = FastList.newListWith(1, 2, 3);
Appendable appendable = new StringBuilder();
list.appendString(appendable, "[", "/", "]");
assertEquals("[1/2/3]", appendable.toString());

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

List<Object> list = ...;
ListAdapter.adapt(list).makeString(",");

Примечание: Я коммиттер коллекций Eclipse.

2 голосов
/ 25 апреля 2016

Если вы используете Spring MVC, попробуйте выполнить следующие действия.

import org.springframework.util.StringUtils;

List<String> groupIds = new List<String>;   
groupIds.add("a");    
groupIds.add("b");    
groupIds.add("c");

String csv = StringUtils.arrayToCommaDelimitedString(groupIds.toArray());

Это приведет к a,b,c

1 голос
/ 16 сентября 2008

С переменными аргументами Java 5 вам не нужно явно вставлять все строки в коллекцию или массив:

import junit.framework.Assert;
import org.junit.Test;

public class StringUtil
{
    public static String join(String delim, String... strings)
    {
        StringBuilder builder = new StringBuilder();

        if (strings != null)
        {
            for (String str : strings)
            {
                if (builder.length() > 0)
                {
                    builder.append(delim).append(" ");
                }
                builder.append(str);
            }
        }           
        return builder.toString();
    }
    @Test
    public void joinTest()
    {
        Assert.assertEquals("", StringUtil.join(",", null));
        Assert.assertEquals("", StringUtil.join(",", ""));
        Assert.assertEquals("", StringUtil.join(",", new String[0]));
        Assert.assertEquals("test", StringUtil.join(",", "test"));
        Assert.assertEquals("foo, bar", StringUtil.join(",", "foo", "bar"));
        Assert.assertEquals("foo, bar, x", StringUtil.join(",", "foo", "bar", "x"));
    }
}
1 голос
/ 15 сентября 2008

Вам, вероятно, следует использовать StringBuilder с методом append для построения вашего результата, но в остальном это такое же хорошее решение, как и в Java.

1 голос
/ 15 сентября 2008

Почему бы вам не сделать в Java то же самое, что вы делаете в ruby, то есть создать разделенную разделителями строку только после того, как вы добавили все части в массив?

ArrayList<String> parms = new ArrayList<String>();
if (someCondition) parms.add("someString");
if (anotherCondition) parms.add("someOtherString");
// ...
String sep = ""; StringBuffer b = new StringBuffer();
for (String p: parms) {
    b.append(sep);
    b.append(p);
    sep = "yourDelimiter";
}

Возможно, вы захотите переместить цикл for в отдельный вспомогательный метод, а также использовать StringBuilder вместо StringBuffer ...

Редактировать : исправлен порядок добавления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...