Java 8中的字符串数组流

13

我有一个格式为单个字符串:

row1col1 row1col2
row2col1 row2col2
row3col1 row3col2

我想提取每个项目并建立一个具有以下属性的对象数组:

and so on...

new MyObject(row1col1, row1col2); 

我是Java 8和流式处理的新手,想知道如何在不使用循环的情况下实现这一点。

通常我会使用 String.split('\n') 将行累积到一个字符串数组中

然后使用循环,对于每一行,在空格分隔符上再次进行拆分,并使用结果数组的两个元素(row1col1 row1col2)构建我的对象,直到没有更多的行可以处理为止。

像这样:

String sausage = "row1col1 row1col2\nrow2col1 row2col2\nrow3col1 row3col2";
String[] rows = sausage.split("\n");

for (String row : rows) {
    String[] objectData = u.split("\\s+");
    MyObject myObject = new MyObject(objectData[0], objectData[1]);
    myObjectList.add(myObject);
}

有人能解释一下如何使用流实现相同的效果,以及背后的机制是什么让我这样做呢?

当增加元素数量时,这是否是一种有效的思考方式?因为从我所看到的所有示例中,流都专注于过滤、收集或在给定一组元素的情况下,应用某些条件检索一个较小的集合。


2
您希望整个数据流作为一个数组保存在内存中,还是想要逐行处理一组数据,并重复逐行处理循环? - Tschallacka
我实际上是从文件中加载流,所以我认为它在处理之前全部读入内存了,对吗? - Lucian Enache
@LucianEnache,不一定。这取决于你的阅读方式。 - shmosel
1
是的,但不同之处在于,您是否想将所有字符串加载到内存中(比如说2MB),然后将其拆分为数组(另外4MB),然后迭代这些数组并将它们转换为您自己的对象(另外xMB),这样会产生大量垃圾内存。或者您可以跳过所有这些步骤,直接将其全部处理为您自己的对象,从而允许快速进行垃圾清理,并减少内存不足的风险。这就是我问的原因。 - Tschallacka
2
@MichaelDibbets 现在我明白了,从技术角度来说,您希望在加载时进行处理,所以我想最好的方法是使用一个inputStream并进行读取。 - Lucian Enache
2个回答

11

一种简单的方法是使用换行符创建一个Pattern对象,然后将输入的String拆分为Stream。然后,每一行都用空格拆分(仅保留两个部分),并映射到一个MyObject。最后,使用这些结果构建一个数组。

public static void main(String[] args) {
    String str = "row1col1 row2col2\r\nrow2col1 row2col2\r\nrow3col1 row3col2";

    MyObject[] array =
        Pattern.compile(System.lineSeparator(), Pattern.LITERAL)
               .splitAsStream(str)
               .map(s -> s.split("\\s+", 2))
               .map(a -> new MyObject(a[0], a[1]))
               .toArray(MyObject[]::new);

    System.out.println(Arrays.toString(array));
}
使用 splitAsStream 可以比使用 Stream.of(...) 更有效,如果输入的 String 非常长。在代码中我假设了String 的行分隔符是操作系统的默认行分隔符 (System.lineSeparator()),但如果不是,你可以进行更改。另外,如果你从文件中读取数据,你可以使用 Files.lines() 来获取文件中所有行的一个 Stream
MyObject[] array = Files.lines(path)
                        .map(s -> s.split("\\s+", 2))
                        .map(a -> new MyObject(a[0], a[1]))
                        .toArray(MyObject[]::new);

System.out.println(Arrays.toString(array));

7
您可以生成一个代表单个MyObject实例的String流,并将每个String转换为MyObject实例(首先再次分割它们,然后构造MyObject实例):
List<MyObject> list = 
   Stream.of(inputString.split("\n"))
      .map (s -> s.split(" "))
      .filter (arr -> arr.length == 2) // this validation may not be necessary
                                       // if you are sure each line contains 2 tokens
      .map (arr -> new MyObject(arr[0],arr[1]))
      .collect(Collectors.toList());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接