将ArrayList转换为字符串的最佳方法

时间:2009-03-01 02:58:11

标签: java string arraylist

我想要一个ArrayList完全输出为String。基本上我想使用由制表符分隔的每个元素的toString按顺序输出它。有没有快速的方法来做到这一点?你可以循环它(或删除每个元素)并将它连接到一个字符串,但我认为这将是非常缓慢的。

28 个答案:

答案 0 :(得分:751)

在Java 8或更高版本中:

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

如果list不是String类型,可以使用连接收集器:

String listString = list.stream().map(Object::toString)
                        .collect(Collectors.joining(", "));

答案 1 :(得分:373)

如果您碰巧在Android上执行此操作,那么有一个很好的实用工具TextUtils,它有.join(String delimiter, Iterable)方法。

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

显然在Android之外没什么用处,但我想把它添加到这个帖子......

答案 2 :(得分:307)

基本上,使用循环迭代ArrayList是唯一的选择:

请勿使用此代码,请继续阅读本答案的底部,了解为什么不合适,以及应使用哪些代码:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

String listString = "";

for (String s : list)
{
    listString += s + "\t";
}

System.out.println(listString);

实际上,字符串连接将会很好,因为javac编译器会将字符串连接优化为append上的一系列StringBuilder操作。以下是上述程序中for循环中字节码反汇编的一部分:

   61:  new #13; //class java/lang/StringBuilder
   64:  dup
   65:  invokespecial   #14; //Method java/lang/StringBuilder."<init>":()V
   68:  aload_2
   69:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  aload   4
   74:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   77:  ldc #16; //String \t
   79:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   82:  invokevirtual   #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

可以看出,编译器使用StringBuilder来优化该循环,因此性能不应该是一个大问题。

(好的,第二眼,StringBuilder正在循环的每次迭代中被实例化,因此它可能不是最有效的字节码。实例化和使用显式StringBuilder可能会产生更好的效果性能。)

事实上,我认为任何类型的输出(无论是磁盘还是屏幕)都至少要比担心字符串连接的性能慢一个数量级。

编辑:正如评论中指出的,上述编译器优化确实在每次迭代时创建了StringBuilder的新实例。 (我之前已经注意到了。)

要使用的最优化技术是Paul Tomblin的响应,因为它只实例化StringBuilder循环之外的单个for对象。

将以上代码重写为:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder();
for (String s : list)
{
    sb.append(s);
    sb.append("\t");
}

System.out.println(sb.toString());

只会在循环外部实例化StringBuilder,并且只在循环内对append方法进行两次调用,如此字节码中所示(显示{{1}的实例化和循环):

StringBuilder

因此,手优化确实应该更好,因为 // Instantiation of the StringBuilder outside loop: 33: new #8; //class java/lang/StringBuilder 36: dup 37: invokespecial #9; //Method java/lang/StringBuilder."<init>":()V 40: astore_2 // [snip a few lines for initializing the loop] // Loading the StringBuilder inside the loop, then append: 66: aload_2 67: aload 4 69: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 72: pop 73: aload_2 74: ldc #15; //String \t 76: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 79: pop 循环的内部更短,并且不需要在每次迭代时实例化for

答案 3 :(得分:215)

下载Apache Commons Lang并使用方法

 StringUtils.join(list)

 StringUtils.join(list, ", ") // 2nd param is the separator.

当然,您可以自己实现它,但是他们的代码已经过全面测试,可能是最好的实现。

我是Apache Commons库的忠实粉丝,我也认为它是Java标准库的一个很好的补充。

答案 4 :(得分:137)

这是一个非常古老的问题,但我想我也可以添加一个更现代的答案 - 使用Joiner中的Guava类:

String joined = Joiner.on("\t").join(list);

答案 5 :(得分:77)

列表更改为可读且有意义的字符串确实是每个人都可能遇到的常见问题。

案例1 。如果你的类路径中有apache的StringUtils(来自rogerdpack和Ravi Wallau):

import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);

案例2 。如果您只想使用JDK(7)中的方法:

import java.util.Arrays;
String str = Arrays.toString(myList.toArray()); 

永远不要自己制造轮子,不要在这个单线任务中使用循环。

答案 6 :(得分:56)

如果您正在寻找快速的单行程序,从Java 5开始,您可以这样做:

myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")

此外,如果您的目的只是打印出内容并且不太关心“\ t”,那么您可以这样做:

myList.toString()

返回类似

的字符串
  

[str1,str2,str3]

如果您有一个Array(不是ArrayList),那么您可以像这样完成同样的事情:

 Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")

答案 7 :(得分:38)

遍历它并调用toString。没有一种神奇的方式,如果有的话,除了循环之外,你认为它会做什么呢?关于唯一的微优化将是使用StringBuilder而不是String,即使这不是一个巨大的胜利 - 连接字符串变成了StringBuilder的封面,但至少如果你这样写,你可以看到发生了什么。

StringBuilder out = new StringBuilder();
for (Object o : list)
{
  out.append(o.toString());
  out.append("\t");
}
return out.toString();

答案 8 :(得分:36)

大多数Java项目通常都有apache-commons lang。 StringUtils.join()方法非常好,有几种风格可以满足几乎所有需求。

public static java.lang.String join(java.util.Collection collection,
                                    char separator)


public static String join(Iterator iterator, String separator) {
    // handle null, zero and one elements before building a buffer 
    Object first = iterator.next();
    if (!iterator.hasNext()) {
        return ObjectUtils.toString(first);
    }
    // two or more elements 
    StringBuffer buf = 
        new StringBuffer(256); // Java default is 16, probably too small 
    if (first != null) {
        buf.append(first);
    }
    while (iterator.hasNext()) {
        if (separator != null) {
            buf.append(separator);
        }
        Object obj = iterator.next();
        if (obj != null) {
            buf.append(obj);
        }
    }
    return buf.toString();
}
  

参数:

     

集合 - 要加入的值的集合,可以为null

     

分隔符 - 要使用的分隔符

     

返回:已连接的String,如果为null,则为null   null迭代器输入

     

自:   2.3

答案 9 :(得分:15)

Android有一个TextUtil类,您可以使用http://developer.android.com/reference/android/text/TextUtils.html

String implode = TextUtils.join("\t", list);

答案 10 :(得分:13)

处理尾随分隔字符的一种优雅方法是使用Class Separator

StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();

Class Separator的toString方法返回第一次调用的之外的分隔符。因此,我们打印列表而不尾随(或在这种情况下)前导分隔符。

答案 11 :(得分:12)

对于这个简单的用例,您可以使用逗号简单地连接字符串。如果您使用Java 8:

String csv = String.join("\t", yourArray);

否则commons-lang有一个join()方法:

String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");

答案 12 :(得分:7)

ArrayList类(Java Docs)扩展了AbstractList类,它扩展了AbstractCollection类,其中包含toString()方法(Java Docs)。所以你只需写

listName.toString();

Java开发人员已经找到了最有效的方法,并在一个包装精美且文档化的方法中为您提供了这些方法。只需调用该方法即可。

答案 13 :(得分:6)

这是一种O(n)算法(除非你做了一些多线程解决方案,你将列表分成多个子列表,但我认为这不是你所要求的)。

只需使用StringBuilder,如下所示:

StringBuilder sb = new StringBuilder();

for (Object obj : list) {
  sb.append(obj.toString());
  sb.append("\t");
}

String finalString = sb.toString();

StringBuilder将比字符串连接快得多,因为您不会在每个连接上重新实例化String对象。

答案 14 :(得分:5)

如果你碰巧在Android上并且你还没有使用Jack(例如因为它仍然缺乏对Instant Run的支持),并且你想要更多地控制结果字符串的格式化(例如,你会喜欢使用换行符作为元素的分隔符,并碰巧使用/想要使用StreamSupport库(在Java 7或更早版本的编译器上使用流),你可以使用这样的东西(我把这个方法在我的ListUtils类中):

public static <T> String asString(List<T> list) {
    return StreamSupport.stream(list)
            .map(Object::toString)
            .collect(Collectors.joining("\n"));
}

当然,确保在列表对象上实现toString()&#39;类。

答案 15 :(得分:3)

如果您使用的是Eclipse Collections,则可以使用makeString()方法。

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

Assert.assertEquals(
    "one\ttwo\tthree",
    ArrayListAdapter.adapt(list).makeString("\t"));

如果您可以将ArrayList转换为FastList,则可以摆脱适配器。

Assert.assertEquals(
    "one\ttwo\tthree",
    FastList.newListWith("one", "two", "three").makeString("\t"));

注意:我是Eclipse Collections的提交者。

答案 16 :(得分:3)

以下代码可能对您有帮助,

List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
String str = list.toString();
System.out.println("Step-1 : " + str);
str = str.replaceAll("[\\[\\]]", "");
System.out.println("Step-2 : " + str);

输出:

Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3

答案 17 :(得分:3)

可能不是最好的方式,但优雅的方式。

Arrays.deepToString(Arrays.asList(&#34; Test&#34;,&#34; Test2&#34;)

import java.util.Arrays;

    public class Test {
        public static void main(String[] args) {
            System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
        }
    }

输出

[测试,测试2]

答案 18 :(得分:3)

以下是否有任何好处:

List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));   

答案 19 :(得分:3)

List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()

您传递到要用作分隔符的new StringJoiner字符序列。如果您想要执行CSV:new StringJoiner(", ");

答案 20 :(得分:3)

如果你不想要最后一个元素之后的最后一个元素,你必须使用索引进行检查,但是请记住,当列表实现RandomAccess时,这只会“起作用”(即O(n))。 / p>

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder(list.size() * apprAvg); // every apprAvg > 1 is better than none
for (int i = 0; i < list.size(); i++) {
    sb.append(list.get(i));
    if (i < list.size() - 1) {
        sb.append("\t");
    }
}
System.out.println(sb.toString());

答案 21 :(得分:2)

在Java 8中,它很简单。有关整数列表,请参阅示例:

String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "\t" + u).orElse("");

或多行版本(更易于阅读):

String result = Arrays.asList(1,2,3).stream()
    .map(Object::toString)
    .reduce((t, u) -> t + "\t" + u)
    .orElse("");

答案 22 :(得分:1)

要使用制表符分隔而不是使用 println ,您可以使用打印

ArrayList<String> mylist = new ArrayList<String>();

mylist.add("C Programming");
mylist.add("Java");
mylist.add("C++");
mylist.add("Perl");
mylist.add("Python");

for (String each : mylist)
{       
    System.out.print(each);
    System.out.print("\t");
}

答案 23 :(得分:1)

我看到很多依赖于额外资源的例子,但似乎这是最简单的解决方案:(我在自己的项目中使用的)基本上只是从ArrayList转换为Array然后到列表。

listeners: {
    'data-changed': 'test'
},

答案 24 :(得分:0)

您可以使用正则表达式。这是简洁的

System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));

答案 25 :(得分:0)

现在这是一个相当古老的对话,apache commons现在在内部使用StringBuilder:http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line.3045

我们知道这会提高性能,但如果性能至关重要,那么使用的方法可能会有些低效。虽然界面是灵活的并且允许跨不同集合类型的一致行为,但对于列表来说这是有效的,这是原始问题中的集合类型。

我的基础是,我们会产生一些开销,我们可以通过简单地遍历传统for循环中的元素来避免这些开销。相反,在幕后检查并发修改,方法调用等还有一些额外的事情。另一方面,增强的for循环会导致相同的开销,因为迭代器用在Iterable对象(List)上。

答案 26 :(得分:0)

在一行中: 从[12,0,1,78,12]到12 0 1 78 12

String srt= list.toString().replaceAll("\\[|\\]|,","");

答案 27 :(得分:-1)

这个功能怎么样:

public static String toString(final Collection<?> collection) {
    final StringBuilder sb = new StringBuilder("{");
    boolean isFirst = true;
    for (final Object object : collection) {
        if (!isFirst)
            sb.append(',');
        else
            isFirst = false;
        sb.append(object);
    }
    sb.append('}');
    return sb.toString();
}

适用于任何类型的收藏......