问题
如何在处理有序流的最后一项之后但在关闭之前执行操作? 此操作应该能够在流管道中注入(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/