我有一个数组列表,我想把它完全输出为字符串。本质上,我想使用每个元素的toString按顺序输出它,每个元素由制表符分隔。有什么快速的方法吗?你可以循环遍历它(或删除每个元素),并将它连接到一个字符串,但我认为这将是非常缓慢的。
当前回答
将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());
只是永远不要自己建造轮子,不要使用循环这一行任务。
其他回答
如果你碰巧在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项目通常都有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
如果您正在使用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"));
如果可以将数组列表转换为FastList,就可以摆脱适配器。
Assert.assertEquals(
"one\ttwo\tthree",
FastList.newListWith("one", "two", "three").makeString("\t"));
注意:我是Eclipse Collections的提交者。
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。
如果你不想让最后一个元素后面的最后一个\t,你必须使用索引来检查,但请记住,这只在lists实现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());
推荐文章
- 如何在java中格式化持续时间?(如格式H:MM:SS)
- urlencoder .encode(字符串)已弃用,我应该使用什么代替?
- javax.transaction.Transactional vs . org.springframework.transaction.annotation.Transactional
- Java 8接口方法中不允许“同步”的原因是什么?
- 如何找到Java堆大小和内存使用(Linux)?
- c#:如何获得一个字符串的第一个字符?
- String类中的什么方法只返回前N个字符?
- 我可以将c#字符串值转换为转义字符串文字吗?
- 使用Enum实现单例(Java)
- RabbitMQ与通道和连接之间的关系
- buildSessionFactory()配置方法在Hibernate中已弃用?
- Spring MVC -如何获得所有的请求参数在一个地图在Spring控制器?
- 在c#中解析字符串为日期时间
- 如何在Java中按两个字段排序?
- 文件之间的差异。路径中的分隔符和斜杠