Каков наилучший способ создать строку элементов с разделителями в 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 ]

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

Pre Java 8:

Apache Commons Lang - ваш друг здесь - он предоставляет метод соединения, очень похожий на тот, который вы используете в Ruby:

StringUtils.join(java.lang.Iterable,char)


Java 8:

Java 8 обеспечивает соединение из коробки через StringJoiner и String.join(). Фрагменты ниже показывают, как вы можете их использовать:

StringJoiner

StringJoiner joiner = new StringJoiner(",");
joiner.add("01").add("02").add("03");
String joinedString = joiner.toString(); // "01,02,03"

String.join(CharSequence delimiter, CharSequence... elements))

String joinedString = String.join(" - ", "04", "05", "06"); // "04 - 05 - 06"

String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

List<String> strings = new LinkedList<>();
strings.add("Java");strings.add("is");
strings.add("cool");
String message = String.join(" ", strings);
//message returned is: "Java is cool"
51 голосов
/ 15 сентября 2008

Вы можете написать небольшой метод в стиле соединения, который работает с java.util.Lists

public static String join(List<String> list, String delim) {

    StringBuilder sb = new StringBuilder();

    String loopDelim = "";

    for(String s : list) {

        sb.append(loopDelim);
        sb.append(s);            

        loopDelim = delim;
    }

    return sb.toString();
}

Тогда используйте это так:

    List<String> list = new ArrayList<String>();

    if( condition )        list.add("elementName");
    if( anotherCondition ) list.add("anotherElementName");

    join(list, ",");
44 голосов
/ 16 мая 2011

В случае Android класс StringUtils из общего достояния недоступен, поэтому для этого я использовал

android.text.TextUtils.join(CharSequence delimiter, Iterable tokens)

http://developer.android.com/reference/android/text/TextUtils.html

31 голосов
/ 18 сентября 2012

В библиотеке Google Guava имеется com.google.common.base.Joiner класс, который помогает решать такие задачи.

Примеры:

"My pets are: " + Joiner.on(", ").join(Arrays.asList("rabbit", "parrot", "dog")); 
// returns "My pets are: rabbit, parrot, dog"

Joiner.on(" AND ").join(Arrays.asList("field1=1" , "field2=2", "field3=3"));
// returns "field1=1 AND field2=2 AND field3=3"

Joiner.on(",").skipNulls().join(Arrays.asList("London", "Moscow", null, "New York", null, "Paris"));
// returns "London,Moscow,New York,Paris"

Joiner.on(", ").useForNull("Team held a draw").join(Arrays.asList("FC Barcelona", "FC Bayern", null, null, "Chelsea FC", "AC Milan"));
// returns "FC Barcelona, FC Bayern, Team held a draw, Team held a draw, Chelsea FC, AC Milan"

Вот статья о строковых утилитах Guava .

25 голосов
/ 22 марта 2014

В Java 8 вы можете использовать String.join():

List<String> list = Arrays.asList("foo", "bar", "baz");
String joined = String.join(" and ", list); // "foo and bar and baz"

Также посмотрите этот ответ для примера Stream API.

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

Вы можете обобщить это, но в Java нет объединения, как вы хорошо сказали.

Это может работать лучше.

public static String join(Iterable<? extends CharSequence> s, String delimiter) {
    Iterator<? extends CharSequence> iter = s.iterator();
    if (!iter.hasNext()) return "";
    StringBuilder buffer = new StringBuilder(iter.next());
    while (iter.hasNext()) buffer.append(delimiter).append(iter.next());
    return buffer.toString();
}
15 голосов
/ 15 сентября 2008

Используйте подход, основанный на java.lang.StringBuilder! («Изменяемая последовательность символов.»)

Как вы упомянули, все эти объединения строк создают строки повсюду. StringBuilder этого не сделает.

Почему StringBuilder вместо StringBuffer? Из StringBuilder Javadoc:

Там, где это возможно, рекомендуется использовать этот класс вместо StringBuffer, так как он будет быстрее в большинстве реализаций.

12 голосов
/ 22 декабря 2014

в Java 8 вы можете сделать это следующим образом:

list.stream().map(Object::toString)
                        .collect(Collectors.joining(delimiter));

если в списке есть нули, вы можете использовать:

list.stream().map(String::valueOf)
                .collect(Collectors.joining(delimiter))
10 голосов
/ 15 сентября 2008

Я бы использовал Google Collections. Есть хорошая возможность присоединиться.
http://google -collections.googlecode.com / SVN / багажник / Javadoc / index.html? COM / Google / общие / база / Join.html

Но если бы я захотел написать это сам,

package util;

import java.util.ArrayList;
import java.util.Iterable;
import java.util.Collections;
import java.util.Iterator;

public class Utils {
    // accept a collection of objects, since all objects have toString()
    public static String join(String delimiter, Iterable<? extends Object> objs) {
        if (objs.isEmpty()) {
            return "";
        }
        Iterator<? extends Object> iter = objs.iterator();
        StringBuilder buffer = new StringBuilder();
        buffer.append(iter.next());
        while (iter.hasNext()) {
            buffer.append(delimiter).append(iter.next());
        }
        return buffer.toString();
    }

    // for convenience
    public static String join(String delimiter, Object... objs) {
        ArrayList<Object> list = new ArrayList<Object>();
        Collections.addAll(list, objs);
        return join(delimiter, list);
    }
}

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

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

Apache commons У класса StringUtils есть метод join.

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