使用Java 8将对象列表转换为从toString()方法获得的字符串


206

Java 8中有很多有用的新事物。例如,我可以在对象列表上使用流进行迭代,然后对Object实例的特定字段中的值求和。例如

public class AClass {
  private int value;
  public int getValue() { return value; }
}

Integer sum = list.stream().mapToInt(AClass::getValue).sum();

因此,我问是否有任何方法可以构建一个StringtoString()一行实例中的方法输出连接在一起的方法。

List<Integer> list = ...

String concatenated = list.stream().... //concatenate here with toString() method from java.lang.Integer class

假设list包含整数12并且3,我希望concatenated"123""1,2,3"


Answers:


368

一种简单的方法是将列表项添加到 StringBuilder

   List<Integer> list = new ArrayList<>();
   list.add(1);
   list.add(2);
   list.add(3);

   StringBuilder b = new StringBuilder();
   list.forEach(b::append);

   System.out.println(b);

您也可以尝试:

String s = list.stream().map(e -> e.toString()).reduce("", String::concat);

说明:map将Integer流转换为String流,然后将其简化为所有元素的串联。

注意:这是normal reduction在O(n 2)中执行的

为更好的性能使用StringBuildermutable reduction类似F.伯乐的答案。

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

参考:流减少


2
是的,不是内联解决方案,而是解决方案。
mat_boy 2014年

没有得到。你在期待什么?
2014年

2
我不明白为什么“在O(n2)中执行的正常归约”。对我来说,它“看起来”更像O(n)...
datahaki

2
@datahaki我不是Java专家,但是我猜想迭代字符串串联(减少)需要在每次迭代时进行数组(重新)分配,这使其变为O(n ^ 2)。join另一方面,将在分配最终字符串之前预先分配一个足够大的数组,以存储最终字符串,使其为O(n)。
Eli Korvigo

2
很好的小费。也许您可以使用“ ::”符号进行简化。因此,list.stream().map(Object::toString).reduce("", String::concat)。使用map e-> e.toString()有点多余。
e2a

194

joiningAPI中有一个收集器。这是中的静态方法Collectors

list.stream().map(Object::toString).collect(Collectors.joining(","))

由于的必要调用,因此并不完美toString,但可以正常工作。不同的定界符是可能的。


7
为了完整起见:要使该确切的代码正常工作,您需要import static java.util.stream.Collectors.joining;
Mahdi

7
为什么我们需要映射和显式的“ toString”?如果收集器期望使用String元素,则应隐式调用转换,不是吗?
巴塞尔Shishani

10

万一有人在没有Java 8的情况下尝试这样做,这是一个很好的技巧。List.toString()已经返回了一个如下所示的集合:

[1,2,3]

根据您的特定要求,只要列表项中不包含[]或,便可以对其进行后处理。

例如:

list.toString().replace("[","").replace("]","") 

或者,如果您的数据可能包含方括号,请执行以下操作:

String s=list.toString();
s = s.substring(1,s.length()-1) 

将为您提供相当合理的输出。

每行可以创建一个数组项,如下所示:

list.toString().replace("[","").replace("]","").replaceAll(",","\r\n")

我使用此技术从小型应用程序中的列表制作html工具提示,内容如下:

list.toString().replace("[","<html>").replace("]","</html>").replaceAll(",","<br>")

如果有数组,则以Arrays.asList(list).toString()开头

我将完全拥有这样一个事实,即这不是最佳选择,但它并没有您想像的那样效率低下,并且非常容易阅读和理解。但是,它非常不灵活-特别是如果数据中可能包含逗号,则不要尝试使用replaceAll分隔元素,如果数据中包含方括号,则不要使用substring版本,但是对于数字数组来说,完善。


尽管通常可以使用,但不能保证- List不会强制的结构toString()AbstractCollection但是,默认情况下确实使用此结构,并且我认为ListJava SE中的所有通用实现也都可以。例如,org.springframework.util.AutoPopulatingList在Spring中没有实现toString(),因此将返回例如“ org.springframework.util.AutoPopulatingList@170a1”。
M. Justin

Arrays.toString()与相比Arrays.asList(list).toString(),它会是一个更好的选择,因为它被定义为返回一个等效的字符串,它更加简洁,并且不需要创建其他对象。
M. Justin

@ M.Justin对于这个答案的数组部分来说,还不错,但是普通的“列表”呢?您实际上不能在其上使用Arrays.toString()。您如何建议在您提到的AutoPopulatingList之类的东西上使用此技术?也许:new ArrayList(autoPopulatingList).toString()?或者我猜您可以将其转换为数组。也许如果您遇到这样的问题,您应该希望自己在1.8或更高版本上,并可以在该线程中使用其他答案之一……
Bill K

5

其他答案很好。但是,您也可以将Collectors.toList()作为参数传递给Stream.collect(),以将元素作为ArrayList返回。

System.out.println( list.stream().map( e -> e.toString() ).collect( toList() ) );

如果使用System.out.print(ln)(list),它将使用toString()元素的方法来打印列表。因此,这段代码只是重复toStringList 内部发生的事情。
Shirkam '17

1
除非要导入静态对象,否则应为Collectors.toList()。
mwieczorek '18

是的...我导入了静态示例。我在答案的正文中说了“ Collectors.toList()”……;)
Eddie B


2

String API中有一个方法用于那些“字符串的连接列表”用例,您甚至不需要Stream。

List<String> myStringIterable = Arrays.asList("baguette", "bonjour");

String myReducedString = String.join(",", myStringIterable);

// And here you obtain "baguette,bonjour" in your myReducedString variable

1
List<String> list = Arrays.asList("One", "Two", "Three");
    list.stream()
            .reduce("", org.apache.commons.lang3.StringUtils::join);

要么

List<String> list = Arrays.asList("One", "Two", "Three");
        list.stream()
                .reduce("", (s1,s2)->s1+s2);

这种方法还允许您从对象列表构建字符串结果。

List<Wrapper> list = Arrays.asList(w1, w2, w2);
        list.stream()
                .map(w->w.getStringValue)
                .reduce("", org.apache.commons.lang3.StringUtils::join);

在这里,reduce函数允许您具有一些想要向其附加新字符串的初始值,例如:

 List<String> errors = Arrays.asList("er1", "er2", "er3");
            list.stream()
                    .reduce("Found next errors:", (s1,s2)->s1+s2);

1

测试Shail016bpedroso答案(https://stackoverflow.com/a/24883180/2832140)中建议的两种方法,循环内的简单StringBuilder+ 似乎比执行快得多。append(String)forlist.stream().map([...]

示例:此代码Map<Long, List<Long>>使用list.stream().map([...]以下内容遍历构建json字符串的过程:

if (mapSize > 0) {
    StringBuilder sb = new StringBuilder("[");

    for (Map.Entry<Long, List<Long>> entry : threadsMap.entrySet()) {

        sb.append("{\"" + entry.getKey().toString() + "\":[");
        sb.append(entry.getValue().stream().map(Object::toString).collect(Collectors.joining(",")));
    }
    sb.delete(sb.length()-2, sb.length());
    sb.append("]");
    System.out.println(sb.toString());
}

在我的开发VM上,junit通常需要0.35到1.2秒才能执行测试。而使用下面的代码,则需要0.15至0.33秒:

if (mapSize > 0) {
    StringBuilder sb = new StringBuilder("[");

    for (Map.Entry<Long, List<Long>> entry : threadsMap.entrySet()) {

        sb.append("{\"" + entry.getKey().toString() + "\":[");

        for (Long tid : entry.getValue()) {
            sb.append(tid.toString() + ", ");
        }
        sb.delete(sb.length()-2, sb.length());
        sb.append("]}, ");
    }
    sb.delete(sb.length()-2, sb.length());
    sb.append("]");
    System.out.println(sb.toString());
}

0

我们可以尝试一下吗?

public static void main(String []args){
        List<String> stringList = new ArrayList<>();
        for(int i=0;i< 10;i++){
            stringList.add(""+i);
        }
        String stringConcated = String.join(",", stringList);
        System.out.println(stringConcated);

    }

0
String actual = list.stream().reduce((t, u) -> t + "," + u).get();

7
通常,最好在您的帖子中添加一个解释,以说明代码的工作原理。这使新开发人员可以了解代码的作用。
卡勒布

1
@CalebKleveter可以将a简化List为单个String元素,并用逗号(,)分隔每个元素。
乔·阿尔莫

2
仅当list为List <String>时,您的解决方案才有效。OP未指定此类。在他的问题中,甚至指出了一个List <Integer>。在这种情况下,您的代码无法编译。
RubioRic

0

我将使用streams api将整数流转换为单个字符串。提供的某些答案的问题在于,由于生成了String,它们会生成O(n ^ 2)运行时。更好的解决方案是使用StringBuilder,然后将字符串连接在一起作为最后一步。

//              Create a stream of integers 
    String result = Arrays.stream(new int[]{1,2,3,4,5,6 })                
            // collect into a single StringBuilder
            .collect(StringBuilder::new, // supplier function
                    // accumulator - converts cur integer into a string and appends it to the string builder
                    (builder, cur) -> builder.append(Integer.toString(cur)),
                    // combiner - combines two string builders if running in parallel
                    StringBuilder::append) 
            // convert StringBuilder into a single string
            .toString();

通过将对象集合转换为单个字符串,可以使此过程更进一步。

// Start with a class definition
public static class AClass {
    private int value;
    public int getValue() { return value; }
    public AClass(int value) { this.value = value; }

    @Override
    public String toString() {
        return Integer.toString(value);
    }
}

// Create a stream of AClass objects
        String resultTwo = Arrays.stream(new AClass[]{
                new AClass(1),
                new AClass(2),
                new AClass(3),
                new AClass(4)
        })
                // transform stream of objects into a single string
                .collect(StringBuilder::new,
                        (builder, curObj) -> builder.append(curObj.toString()),
                        StringBuilder::append
                )
            // finally transform string builder into a single string
            .toString();

-1

使用Java 8+

String s = Arrays.toString(list.stream().toArray(AClass[]::new));

这不是最有效的方法,但是它是一种使用少量代码的解决方案。


-2

另外,您可以这样做。

    List<String> list = Arrays.asList("One", "Two", "Three");
    String result = String.join(", ", list);
    System.out.println(result);

仅当list为List <String>时,您的解决方案才有效。OP未指定此类。在他的问题中,甚至指出了一个List <Integer>。
RubioRic
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.