我有一个数组列表,我想把它完全输出为字符串。本质上,我想使用每个元素的toString按顺序输出它,每个元素由制表符分隔。有什么快速的方法吗?你可以循环遍历它(或删除每个元素),并将它连接到一个字符串,但我认为这将是非常缓慢的。


当前回答

对于使用制表符而不是使用println进行分离,您可以使用print

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");
}

其他回答

如果你碰巧在Android上做这个,有一个很好的实用工具叫做TextUtils,它有一个.join(字符串分隔符,Iterable)方法。

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

显然在Android之外没有太多用处,但我想把它添加到这个线程中…

Java 8引入了一个字符串。Join(分隔符,列表)方法;请看维塔利·费连科的回答。

在Java 8之前,使用循环遍历数组列表是唯一的选择:

不要使用这个代码,继续阅读这个答案的底部,看看为什么它是不可取的,以及应该使用哪些代码:

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编译器无论如何都会将字符串连接优化为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的响应,因为它只在for循环之外实例化一个StringBuilder对象。

将上述代码改写为:

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方法进行两次调用,如下字节码所示(它显示了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循环的内部更短,并且不需要在每次迭代中实例化StringBuilder。

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

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

此外,如果你的目的只是打印出内容,不太关心“\t”,你可以简单地这样做:

myList.toString()

哪个返回一个字符串

[str1, str2, str3]

如果你有一个数组(不是ArrayList),那么你可以像这样完成:

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

在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("");

更新-一个更短的版本

String result = Arrays.asList(1,2,3).stream()
                .map(Object::toString)
                .collect(Collectors.joining("\t"));

大多数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();
}

参数: collection -要连接在一起的值的集合,可以为空 Separator -要使用的分隔符 返回:连接的字符串,如果为空 空迭代器输入 自: 2.3