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

Jua*_*esa 353 java string arraylist

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

Vit*_*nko 818

在Java 8或更高版本中:

String listString = String.join(", ", list);
Run Code Online (Sandbox Code Playgroud)

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

String listString = list.stream().map(Object::toString)
                        .collect(Collectors.joining(", "));
Run Code Online (Sandbox Code Playgroud)

  • 我不敢相信,直到Java 8才能添加它. (134认同)
  • 这个答案应该多投票!没有黑客,没有库和没有循环. (40认同)
  • 这不适用于OP所说的.String.join作为第二个参数Iterable <?扩展CharSequence>.因此,如果你想要显示一个List <String>,它就有效,但是如果你有List <MyObject>,它将*不会*按照OP的要求调用toString() (4认同)
  • 为什么这不是第一个(并且被接受的)答案..我总是向下滚动,直到我知道它在那里..优雅和简洁 (3认同)
  • 需要 Android API 26+ (2认同)
  • @Jack,因为当 2009 年另一个答案被接受时,Java 8 还没有出来。 (2认同)

JJ *_*wax 382

如果您碰巧在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);
Run Code Online (Sandbox Code Playgroud)

显然没有多少在Android之外使用,但想通知我会把它添加到这个线程......

  • `org.apache.lang3.StringUtils`几乎一样,所以你的答案在Android之外绝对有用了:) (5认同)
  • 这个答案的受欢迎程度(目前投票最高的一个)告诉你,许多java问题源于Android开发 (2认同)
  • 我敢打赌你被派到这个地球是为了解决我的问题:) (2认同)
  • 你救了我的命。&lt;3 (2认同)

coo*_*ird 316

基本上,使用循环迭代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);
Run Code Online (Sandbox Code Playgroud)

事实上,字符串连接将会很好,因为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;
Run Code Online (Sandbox Code Playgroud)

可以看出,编译器通过使用a来优化该循环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());
Run Code Online (Sandbox Code Playgroud)

只会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
Run Code Online (Sandbox Code Playgroud)

因此,手优化确实应该更好地执行,因为for循环内部更短并且不需要StringBuilder在每次迭代时实例化.

  • 此解决方案在字符串的末尾添加了额外的"\ t",这通常是不期望的,尤其是当您要创建逗号分隔列表或类似内容时.我认为使用Apache Commons或Guava发布的其他解决方案都非常出色. (9认同)
  • 出于性能原因,请考虑使用StringBuilder类而不是仅附加字符串. (8认同)
  • 编译器将优化字符串连接,但每次执行循环时都将创建一个新的StringBuilder对象. (5认同)
  • -1表示使用+ =,在这种情况下它是性能杀手.始终使用StringBuilder重复追加到字符串. (4认同)
  • 这不是最佳答案。在下面的Vitalii中查找Java,在Geewax中查找Android。 (3认同)

Rav*_*lau 228

下载Jakarta Commons Lang并使用该方法

 StringUtils.join(list)

 StringUtils.join(list, ", ") // 2nd param is the separator.
Run Code Online (Sandbox Code Playgroud)

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

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

  • 不幸的是,SO的居民更喜欢重新发明轮子. (56认同)
  • 也在Apache Commons Lang中.用法看起来像`StringUtils.join(list.toArray(),"\ t")` (33认同)
  • 这个特殊的轮子几乎不值得额外依赖. (31认同)
  • @SevaAlekseyev我认为这是值得商榷的.如果您立即添加此依赖项,您将更多地使用它的类.您将使用StringUtils.isNotEmpty而不是使用"if string!= null && string.trim()!=""...您将使用ObjectUtils.equals(),这样您就不必在任何地方检查null.但是如果你等待使用这些库的一个依赖项,你可能永远不会真正使用它们. (24认同)
  • 它最好不会在最后添加额外的标签! (6认同)
  • 另外,使用Apache Commons 3,没有必要将列表转换为数组.只需使用:`StringUtils.join(list,"\ t")`. (3认同)

Jon*_*eet 139

这是一个非常古老的问题,但我想我不妨添加一个更现代的答案 - 使用GuavaJoiner类:

String joined = Joiner.on("\t").join(list);
Run Code Online (Sandbox Code Playgroud)

  • 这是我最喜欢的解决方案.: - >番石榴+1. (2认同)

She*_*g.W 82

List更改为可读且有意义的String实际上是每个人都可能遇到的常见问题.

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

import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);
Run Code Online (Sandbox Code Playgroud)

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

import java.util.Arrays;
String str = Arrays.toString(myList.toArray()); 
Run Code Online (Sandbox Code Playgroud)

永远不要自己制造轮子,不要使用循环来完成这个单线任务.

  • `Arrays.toString(myList.toArray())` - 最简单,最直接的解决方案 (5认同)

Ken*_*hih 59

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

myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Run Code Online (Sandbox Code Playgroud)

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

myList.toString()
Run Code Online (Sandbox Code Playgroud)

它返回一个字符串

[str1,str2,str3]

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

 Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Run Code Online (Sandbox Code Playgroud)

  • 我认为这实际上比上面发布的方法更有效.这样的耻辱就显示在底部.它可能不优雅,但我坚信你的解决方案运行O(n)而其他理论上运行在O(n ^ 2)(因为Java字符串是不可变的,你基本上在每次合并时创建一个新的字符串,它变得更糟,因为结果字符串变大) (3认同)

Pau*_*lin 38

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

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

  • 对于大型阵列,这绝对不是微优化.对于每个字符串连接,单独完成使用StringBuilder的自动转换,这在循环的情况下没有帮助.如果在一个表达式中连接大量元素,则可以. (4认同)

Bri*_*ian 36

大多数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();
}
Run Code Online (Sandbox Code Playgroud)

参数:

collection - 要连接在一起的值的集合,可以为null

separator - 要使用的分隔符

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

自:2.3

  • 这非常好,因为`join(...)`方法有数组和集合的变体. (2认同)

keh*_*ers 16

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

String implode = TextUtils.join("\t", list);
Run Code Online (Sandbox Code Playgroud)


Kha*_*M A 14

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

String csv = String.join("\t", yourArray);
Run Code Online (Sandbox Code Playgroud)

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

String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");
Run Code Online (Sandbox Code Playgroud)


aku*_*uhn 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();
Run Code Online (Sandbox Code Playgroud)

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


gol*_*ove 7

ArrayListclass(Java Docs)扩展了AbstractList类,它扩展了AbstractCollection包含toString()方法(Java Docs)的类.所以你只需写

listName.toString();
Run Code Online (Sandbox Code Playgroud)

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


Mik*_* C. 6

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

只需使用StringBuilder如下:

StringBuilder sb = new StringBuilder();

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

String finalString = sb.toString();
Run Code Online (Sandbox Code Playgroud)

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


amr*_*mra 6

在Java 8中很简单。请参阅示例以获取整数列表:

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

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

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

更新-较短的版本

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

  • 这可能只是一行代码,但在我看来并不简单。对我来说,遍历 List 并将其元素解析为 String 比这更简单。 (3认同)
  • 这也是我的第一印象。但是习惯了之后觉得很赞。例如,您可以添加诸如“过滤器”之类的操作。最后,我更容易阅读代码。 (2认同)
  • 在Java 8中:String.join(“ \ t”,array) (2认同)

Jav*_*deh 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"));
}
Run Code Online (Sandbox Code Playgroud)

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


Pra*_*jal 5

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

String srt= list.toString().replaceAll("\\[|\\]|,","");
Run Code Online (Sandbox Code Playgroud)

  • 1)没有理由再使用这样的代码(截至 4 年前!)。2)此答案不会为问答添加任何内容。 (2认同)