Java8 流线并通过终端线上的操作进行聚合

标签 java java-8 java-stream

问题

如何在处理有序流的最后一项之后但在关闭之前执行操作? 此操作应该能够在流管道中注入(inject)零个或多个项目。

上下文

我有一个非常大的文件,格式如下:

MASTER_REF1
    SUBREF1
    SUBREF2
    SUBREF3
MASTER_REF2
MASTER_REF3
    SUBREF1
    ...

其中 SUBREF(如果有)适用于 MASTER_REF 并且两者都是复杂对象(您可以想象它有点像 JSON)。

乍一看,我尝试了类似的东西:

public void process(Path path){
    MyBuilder builder = new MyBuilder();
    Files.lines(path)
        .map(line->{
            if(line.charAt(0)==' '){
                builder.parseSubRef(line);
                return null;
            }else{
                Result result = builder.build()
                builder.parseMasterRef(line);
                return result;
            }
        })
        //eliminate null
        .filter(Objects::nonNull)
        //some processing on results
        .map(Utils::doSomething)
        //terminal op
        .forEachOrdered(System.out::println);
}

[编辑]在这里使用forEach是一个坏主意......好方法是使用forEachOrdered

但是,由于显而易见的原因,最后一个项目永远不会附加到流中:它仍在构建中。

因此我想知道如何在行处理结束时将其刷新到流中。

最佳答案

你的问题听起来很困惑。当显式调用 close() 方法或使用 try-with-resources 构造时,Stream 将关闭。在您的代码示例中,流根本没有关闭。要在流关闭之前执行自定义操作,您可以在 try-with-resource 语句的末尾编写一些内容。

在您的情况下,您似乎想要将一些虚假条目连接到流中。有 Stream.concat() 方法可以做到这一点:

Stream.concat(Files.lines(path), Stream.of("MASTER"))
      .map(...) // do all your other steps

最后请注意我的 StreamEx增强 Stream API 的库提供了适合解析多行条目的部分缩减方法。使用 StreamEx.groupRuns() 可以完成同样的事情它通过给定的 BiPredicate 将相邻元素组合到中间列表中:

public void process(Path path){
    StreamEx.of(Files.lines(path))
        .groupRuns((line1, line2) -> line2.charAt(0) == ' ')
        // Now Stream elements are List<String> starting with MASTER and having
        // all subref strings after that
        .map(record -> {
           MyBuilder builder = new MyBuilder();
           builder.parseMasterRef(record.get(0));
           record.subList(1, record.size()).forEach(builder::parseSubRef);
           return record.build();
        })
        //eliminate null
        .filter(Objects::nonNull)
        //some processing on results
        .map(Utils::doSomething)
        //terminal op
        .forEach(System.out::println);
}

现在您不需要使用副作用操作。

关于Java8 流线并通过终端线上的操作进行聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33868014/

相关文章:

java 8 在使用 Collectors.toMap 时处理自定义异常

Java 8 流附加错误处理供以后使用

java - Dozer - 在从列表映射到列表时将对象转换为列表?

Java - 模式匹配奇怪的行为

Eclipse、lambda 和 Java 8 模板

Java 8/9 : Can a character in a String be mapped to its indices (using streams)?

Java 8 Streams - 基于条件的迭代器映射和删除

java - 为什么 HashMap String 值转换为大写?

java - 如何在 StreamingOutput 的 Web 服务中保持客户端和服务器连接处于 Activity 状态

java - 如何将 ISO 8601 格式的 DateTime 转换为 Java 中的另一个时区?