首先采用Java 8流,然后调用forEach(...)

时间:2016-11-30 21:03:14

标签: java csv java-8 java-stream

我有一个CSV文件,第一行包含标题。所以我认为使用Java 8流是完美的。

    try (Stream<String> stream = Files.lines(csv_file) ){
        stream.skip(1).forEach( line -> handleLine(line) );
    } catch ( IOException ioe ){
        handleError(ioe);
    }

是否可以获取第一个元素,分析它然后调用forEach方法?像

这样的东西
stream
      .forFirst( line -> handleFirst(line) )
      .skip(1)
      .forEach( line -> handleLine(line) );

此外: 我的CSV文件包含大约1k行,我可以并行处理每一行以加快速度。除了第一行。我需要第一行来初始化项目中的其他对象:/ 那么打开BufferedReader,读取第一行,关闭BufferedReader以及使用并行流可能是快速的吗?

3 个答案:

答案 0 :(得分:6)

通常,您可以使用迭代器来执行此操作:

Stream<Item> stream = ... //initialize your stream
Iterator<Item> i = stream.iterator();
handleFirst(i.next());
i.forEachRemaining(item -> handleRest(item));

在你的程序中,它看起来像这样:

try (Stream<String> stream = Files.lines(csv_file)){
    Iterator<String> i = stream.iterator();
    handleFirst(i.next());
    i.forEachRemaining(s -> handleRest(s));
}

如果你得到1或0行,你可能想要添加一些错误检查,但这应该有用。

答案 1 :(得分:4)

这样做的好方法是让BufferedReader读取您的文件,例如在Files.newBufferedReader(path)的帮助下。然后,您可以拨打nextLine()一次以检索标题行,并lines()获取所有其他行的Stream<String>

try (BufferedReader br = Files.newBufferedReader(csv_file)){
    String header = br.readLine();
    // if header is null, the file was empty, you may want to throw an exception
    br.lines().forEach(line -> handleLine(line));
}

这是有效的,因为第一次调用readLine()会导致缓冲的阅读器读取第一行,因此,由于lines()是通过读取行​​填充的流,因此它会在第二行开始读取线。处理结束时,try-with-resources也会正确关闭缓冲的阅读器。

潜在地,流管道可以并行运行,但是对于像这样的I / O绑定任务,我不希望任何性能提升,除非处理每一行的速度较慢。但在这种情况下要小心forEach:它将同时运行,因此其代码需要是线程安全的。目前还不清楚handleLine方法的作用,但通常情况下,您不需要forEach,可能更喜欢mutable reduction collect,这可以安全地用于并行流。

答案 2 :(得分:0)

我不认为在流管道中有这样做的好方法,但你可以使用流的迭代器来更好地控制迭代:

try (Stream<String> stream = Files.lines(csv_file) ){
    Iterator<String> iter = stream.iterator();
    if (iter.hasNext()) {
        handleFirst(iter.next());
        while (iter.hasNext()) {
            handleLine(iter.next());
        }
    }
} catch ( IOException ioe ){
    handleError(ioe);
}