我有一个ArrayList
我想完全输出为String.基本上我想按顺序输出它,使用toString
由制表符分隔的每个元素.有没有快速的方法来做到这一点?你可以循环它(或删除每个元素)并将它连接到一个字符串,但我认为这将是非常缓慢的.
在Java 8或更高版本中:
String listString = String.join(", ", list);
如果list
不是String类型,可以使用连接收集器:
String listString = list.stream().map(Object::toString) .collect(Collectors.joining(", "));
如果您碰巧在Android上执行此操作,那么这个名为TextUtils的实用程序有一个很好的实用工具,它有一个.join(String delimiter, Iterable)
方法.
Listlist = new ArrayList (); list.add("Item 1"); list.add("Item 2"); String joined = TextUtils.join(", ", list);
显然没有多少在Android之外使用,但想通知我会把它添加到这个线程......
基本上,使用循环迭代ArrayList
是唯一的选择:
不要使用此代码,继续阅读本答案的底部,看看为什么不合适,以及应该使用哪些代码:
ArrayListlist = new ArrayList (); 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."":()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;
可以看出,编译器通过使用a来优化该循环StringBuilder
,因此性能不应该是一个大问题.
(好吧,第二眼,在StringBuilder
循环的每次迭代中都会实例化,因此它可能不是最有效的字节码.实例化和使用显式StringBuilder
可能会产生更好的性能.)
事实上,我认为任何类型的输出(无论是磁盘还是屏幕)都至少要比担心字符串连接的性能慢一个数量级.
编辑:正如评论中指出的,上面的编译器优化确实StringBuilder
在每次迭代时创建了一个新实例.(我之前已经注意到了.)
最优化的技术将是Paul Tomblin的响应,因为它只实例化循环StringBuilder
外的单个对象for
.
将以上代码重写为:
ArrayListlist = new ArrayList (); 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."":()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
在每次迭代时实例化.
下载Jakarta Commons Lang并使用该方法
StringUtils.join(list) StringUtils.join(list, ", ") // 2nd param is the separator.
当然,您可以自己实现它,但是它们的代码经过了全面测试,可能是最好的实现.
我是Jakarta Commons库的忠实粉丝,我也认为它是Java标准库的一个很好的补充.
这是一个非常古老的问题,但我想我不妨添加一个更现代的答案 - 使用Guava的Joiner
类:
String joined = Joiner.on("\t").join(list);
将List更改为可读且有意义的String实际上是每个人都可能遇到的常见问题.
案例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());
永远不要自己制造轮子,不要使用循环来完成这个单线任务.
如果您正在寻找一个快速的单行程序,从Java 5开始,您可以这样做:
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
此外,如果您的目的只是打印出内容并且不太关心"\ t",那么您可以这样做:
myList.toString()
它返回一个字符串
[str1,str2,str3]
如果您有一个Array(而不是ArrayList),那么您可以像这样完成相同的操作:
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
循环遍历它并调用toString.没有一种神奇的方式,如果有的话,除了循环之外,你认为它会做什么呢?关于唯一的微优化将是使用StringBuilder而不是String,即使这不是一个巨大的胜利 - 连接字符串变成了StringBuilder的封面,但至少如果你这样写,你可以看到发生了什么.
StringBuilder out = new StringBuilder(); for (Object o : list) { out.append(o.toString()); out.append("\t"); } return out.toString();
大多数Java项目通常都有可用的apache-commons.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 - 要连接在一起的值的集合,可以为null
separator - 要使用的分隔符
返回:连接的String,如果为null迭代器输入,则返回 null
自:2.3
Android有一个TextUtil类,你可以使用http://developer.android.com/reference/android/text/TextUtils.html
String implode = TextUtils.join("\t", list);
对于这个简单的用例,您可以使用逗号简单地连接字符串.如果您使用Java 8:
String csv = String.join("\t", yourArray);
commons-lang有一个join()方法:
String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");
处理尾随分隔字符的一种优雅方法是使用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方法返回分隔符,第一次调用除外.因此,我们打印列表而不尾随(或在这种情况下)前导分隔符.
ArrayList
class(Java Docs)扩展了AbstractList
类,它扩展了AbstractCollection
包含toString()
方法(Java Docs)的类.所以你只需写
listName.toString();
Java开发人员已经找到了最有效的方法,并在一个包装精美且文档化的方法中为您提供了这些方法.只需调用该方法即可.
这是一种O(n)
算法(除非你做了一些多线程解决方案,你将列表分成多个子列表,但我不认为这是你要求的).
只需使用StringBuilder
如下:
StringBuilder sb = new StringBuilder(); for (Object obj : list) { sb.append(obj.toString()); sb.append("\t"); } String finalString = sb.toString();
这StringBuilder
将比字符串连接快得多,因为您不会String
在每个连接上重新实例化对象.
在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"));
如果你碰巧在Android上并且你还没有使用Jack(例如因为它仍然缺乏对Instant Run的支持),并且你想要更多地控制结果字符串的格式化(例如你想使用换行字符作为元素的分隔符,并碰巧使用/想要使用StreamSupport库(在Java 7或更早版本的编译器上使用流),你可以使用这样的东西(我把这个方法放在我的ListUtils类中):
public staticString asString(List list) { return StreamSupport.stream(list) .map(Object::toString) .collect(Collectors.joining("\n")); }
当然,确保在列表对象的类上实现toString().