连接String对象列表的最佳方法是什么?

时间:2009-02-07 14:51:24

标签: java string list

连接String对象列表的最佳方法是什么?我想这样做:

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

// add elements

if (sList != null)
{
    String listString = sList.toString();
    listString = listString.subString(1, listString.length() - 1);
}

我以某种方式发现它比使用StringBuilder / StringBuffer方法更整洁。

有任何想法/意见吗?

19 个答案:

答案 0 :(得分:307)

使用Apache Commons Lang中的StringUtils.join方法之一。

import org.apache.commons.lang3.StringUtils;

String result = StringUtils.join(list, ", ");

如果您有幸使用Java 8,那么它就更容易了......只需使用String.join

String result = String.join(", ", list);

答案 1 :(得分:130)

使用Java 8 +

String str = list.stream().collect(Collectors.joining())

甚至

String str = String.join("", list);

答案 2 :(得分:44)

您的方法依赖于Java的ArrayList#toString()实现。

虽然Java API中记录了实现并且不太可能发生变化,但它有可能实现。自己实现它更可靠(循环,StringBuilders,递归,无论你更喜欢什么)。

当然,这种做法可能看起来“更整洁”或更“太甜蜜”或“金钱”,但在我看来,这是一种更糟糕的做法。

答案 3 :(得分:41)

codefin答案的变体

public static String concatStringsWSep(Iterable<String> strings, String separator) {
    StringBuilder sb = new StringBuilder();
    String sep = "";
    for(String s: strings) {
        sb.append(sep).append(s);
        sep = separator;
    }
    return sb.toString();                           
}

答案 4 :(得分:25)

如果您正在为Android开发,SDK会提供TextUtils.join

答案 5 :(得分:16)

这是我迄今为止发现的最优雅,最干净的方式:

list.stream().collect(Collectors.joining(delimiter));

答案 6 :(得分:15)

Guava是来自Google的非常简洁的图书馆:

Joiner joiner = Joiner.on(", ");
joiner.join(sList);

答案 7 :(得分:4)

您是否看过这篇Coding Horror博客文章?

The Sad Tragedy of Micro-Optimization Theater

不管它是否“整洁”,我并不感到害羞,但从表现的角度来看,它可能并不重要。

答案 8 :(得分:4)

我更喜欢Java 8中的String.join(list)

答案 9 :(得分:3)

如果你使用的是java 8,你可以编写一个单行代码,而不是依赖ArrayList.toString()实现:

String result = sList.stream()
                     .reduce("", String::concat);

如果您希望使用StringBuffer而不是字符串,因为String::concat的运行时间为O(n^2),您可以先将String转换为StringBuffer

StringBuffer result = sList.stream()
                           .map(StringBuffer::new)
                           .reduce(new StringBuffer(""), StringBuffer::append);

答案 10 :(得分:3)

在我看来,StringBuilder会快速有效。

基本形式看起来像这样:

public static String concatStrings(List<String> strings)
{
    StringBuilder sb = new StringBuilder();
    for(String s: strings)
    {
        sb.append(s);
    }
    return sb.toString();       
}

如果这太简单了(可能是这样),你可以使用类似的方法并添加这样的分隔符:

    public static String concatStringsWSep(List<String> strings, String separator)
{
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < strings.size(); i++)
    {
        sb.append(strings.get(i));
        if(i < strings.size() - 1)
            sb.append(separator);
    }
    return sb.toString();               
}

我同意那些回答这个问题的人,他们说你不应该依赖Java的ArrayList的toString()方法。

答案 11 :(得分:3)

  我以某种方式发现这比它更整洁   使用StringBuilder / StringBuffer   方法

我想这取决于你采取的方法。

AbstractCollection#toString()方法简单地遍历所有元素并将它们附加到StringBuilder。因此,您的方法可能会节省几行代码,但代价是额外的字符串操作。这种权衡是否是一个好的取决于你。

答案 12 :(得分:2)

假设移动指针/将字节设置为null(或者Java实现StringBuilder #setLength)更快,而不是每次通过循环检查条件以查看何时附加分隔符,您可以使用此方法:

public static String Intersperse (Collection<?> collection, String delimiter)
{
    StringBuilder sb = new StringBuilder ();
    for (Object item : collection)
    {
        if (item == null) continue;
        sb.append (item).append (delimiter);
    }
    sb.setLength (sb.length () - delimiter.length ());
    return sb.toString ();
}

答案 13 :(得分:2)

Peter Lawrey的回答的下一个变化,没有在每次循环转换时初始化新字符串

String concatList(List<String> sList, String separator)
{
    Iterator<String> iter = sList.iterator();
    StringBuilder sb = new StringBuilder();

    while (iter.hasNext())
    {
        sb.append(iter.next()).append( iter.hasNext() ? separator : "");
    }
    return sb.toString();
}

答案 14 :(得分:2)

ArrayListAbstractCollection继承了toString() - 方法,即:

public String toString() {
    Iterator<E> i = iterator();
    if (! i.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = i.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! i.hasNext())
            return sb.append(']').toString();
        sb.append(", ");
    }
}

自己构建字符串会更有效率。


如果你真的想在某种List中预先聚合字符串,你应该提供自己的方法来有效地加入它们,例如:像这样:

static String join(Collection<?> items, String sep) {
    if(items.size() == 0)
        return "";

    String[] strings = new String[items.size()];
    int length = sep.length() * (items.size() - 1);

    int idx = 0;
    for(Object item : items) {
        String str = item.toString();
        strings[idx++] = str;
        length += str.length();
    }

    char[] chars = new char[length];
    int pos = 0;

    for(String str : strings) {
        str.getChars(0, str.length(), chars, pos);
        pos += str.length();

        if(pos < length) {
            sep.getChars(0, sep.length(), chars, pos);
            pos += sep.length();
        }
    }

    return new String(chars);
}

答案 15 :(得分:0)

使用Functional Java库,导入以下内容:

import static fj.pre.Monoid.stringMonoid;
import static fj.data.List.list;
import fj.data.List;

...然后你可以这样做:

List<String> ss = list("foo", "bar", "baz");
String s = stringMonoid.join(ss, ", ");

或者,通用方式,如果您没有字符串列表:

public static <A> String showList(List<A> l, Show<A> s) {
  return stringMonoid.join(l.map(s.showS_()), ", ");
}

答案 16 :(得分:0)

如果你的依赖项中有json。你可以使用new JSONArray(list).toString()

答案 17 :(得分:0)

在java 8中,您还可以使用reducer,例如:

public static String join(List<String> strings, String joinStr) {
    return strings.stream().reduce("", (prev, cur) -> prev += (cur + joinStr));
}

答案 18 :(得分:0)

根据性能需求和要添加的元素数量,这可能是一个不错的解决方案。如果元素数量很高,Arraylist重新分配内存可能会比StringBuilder慢一点。