将ArrayList转换为string的最佳方法

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

基本上,使用循环遍历ArrayList是唯一的select:

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

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

事实上,string连接将会很好,因为javac编译器会将string连接优化为StringBuilder上的一系列append操作。 下面是从上述程序的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优化了这个循环,所以性能不应该成为一个大问题。

(OK,乍一看, StringBuilder正在循环的每次迭代中被实例化,所以它可能不是最有效的字节码。实例化和使用显式的StringBuilder可能会产生更好的性能。

实际上,我认为有任何输出(不pipe是磁盘还是屏幕),至less比不必担心string连接的性能要慢一个数量级。

编辑:正如在注释中指出的,上述编译器优化确实在每次迭代中创build一个新的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的实例化和循环)所certificate的那样:

  // 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 8或更高版本中:

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

如果list不是Stringtypes,则可以使用join的收集器:

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

如果你碰巧在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以外显然没有多less用处,但是我想把它添加到这个线程中…

下载Jakarta Commons Lang并使用该方法

  StringUtils.join(list) 

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

我是Jakarta Commons库的忠实粉丝,我也认为这是Java Standard Library的一个很好的补充。

这是一个相当古老的问题,但我想我不妨添加一个更现代的答案 – 使用Guava的Joiner类:

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

列表更改为可读和有意义的string是每个人都可能遇到的常见问题。

案例1 。 如果你的类path中有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()); 

只是从来没有build立自己的车轮,不要使用循环这个单线的任务。

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

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

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

 myList.toString() 

它返回一个string

[str1,str2,str3]

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

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

循环浏览并调用toString。 没有什么神奇的方法,如果有的话,你认为在循环之外它会做什么? 关于唯一的微型优化是使用StringBuilder而不是String,即使这不是一个巨大的胜利 – 连接string变成了StringBuilder的封面,但至less如果你这样写,你可以看到发生了什么事情。

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

大多数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迭代器input,则返回 null

由于:2.3

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

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

处理尾随分隔符的优雅方法是使用类分隔符

 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方法返回第一个调用之外的分隔符。 因此,我们打印列表没有拖尾(或在这种情况下)领先的分隔符。

 Arrays.toString (current_array) 

这是一种O(n)algorithm,除非你做了一些multithreading解决scheme,把列表分成多个子列表,但我不认为这就是你要求的。

只需使用一个StringBuilder ,如下所示:

 StringBuilder sb = new StringBuilder(); for (Object obj : list) { sb.append(obj.toString()); sb.append("\t"); } String finalString = sb.toString(); 

StringBuilder比string连接要快很多,因为你不会在每个连接上重新实例化一个String对象。

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

 listName.toString(); 

Java开发人员已经find了最有效的方法,并给出了一个很好的打包和logging的方法。 只需调用该方法。

如果你碰巧在Android上,并且你还没有使用Jack(例如,因为它仍然缺乏对即时运行的支持),并且你想要更多地控制结果string的格式(例如,你想使用换行符作为元素的分隔符),并且恰好使用/想要使用StreamSupport库(用于在Java 7或更早版本的编译器中使用stream),可以使用类似这样的方法(将此方法放在我的ListUtils类中):

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

当然,确保在你的列表对象的类上实现toString()。

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

Arrays.deepToString(Arrays.asList(“Test”,“Test2”)

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

产量

[testing,testing2]

如果您使用Eclipse集合 ,则可以使用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集合的提交者。

如果每个元素都有一个不平凡的string表示forms,并且希望插入制表符,则唯一的方法就是循环。

下面的代码可能会帮助你,

 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 

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

以下会有什么好处:

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

如果你不想最后一个元素后面的最后一个元素,你必须使用索引来检查,但是记住当列表实现RandomAccess时,这只是“工作”(即O(n))。

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

你可以使用这个正则expression式。 这是如此简洁

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

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

  List<Account> accounts = new ArrayList<>(); public String accountList() { Account[] listingArray = accounts.toArray(new Account[accounts.size()]); String listingString = Arrays.toString(listingArray); return listingString; } 
 List<String> stringList = getMyListOfStrings(); StringJoiner sj = new StringJoiner(" "); stringList.stream().forEach(e -> sj.add(e)); String spaceSeparated = sj.toString() 

你传递给你想用作分隔符的new StringJoiner字符序列。 如果你想做一个CSV: new StringJoiner(", ");

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

我们知道这会提高性能,但是如果性能很关键,那么使用的方法可能会有些低效。 尽pipe接口是灵活的,并且将允许跨不同的集合types的一致的行为,但对于列表来说,这是低效的,这是原始问题中集合的types。

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

要分开使用制表符而不是使用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"); } 

这个函数怎么样:

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

它适用于任何types的集合…